gapipy


Namegapipy JSON
Version 2.36.0 PyPI version JSON
download
home_pagehttps://github.com/gadventures/gapipy
SummaryPython client for the G Adventures REST API
upload_time2024-05-30 19:10:08
maintainerNone
docs_urlNone
authorG Adventures
requires_pythonNone
licenseMIT
keywords gapipy
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            G API Python Client
===================

.. image:: https://badge.fury.io/py/gapipy.svg
    :target: http://badge.fury.io/py/gapipy

A client for the G Adventures REST API (https://developers.gadventures.com)

* GitHub Repository: https://github.com/gadventures/gapipy/
* Documentation: http://gapipy.readthedocs.org.
* Free software: MIT License


Quick Start
-----------

.. code-block:: python

   >>> from gapipy import Client
   >>> api = Client(application_key='MY_SECRET_KEY')

   >>> # Get a resource by id
   >>> tour_dossier = api.tour_dossiers.get(24309)
   >>> tour_dossier.product_line
   u'AHEH'
   >>> tour_dossier.departures.count()
   134
   >>> tour_dossier.name
   u'Essential India'
   >>> itinerary = tour_dossier.structured_itineraries[0]
   >>> {day.day: day.summary for day in itinerary.days[:3]}
   {1: u'Arrive at any time. Arrival transfer included through the G Adventures-supported Women on Wheels project.',
   2: u'Take a morning walk through the city with a young adult from the G Adventures-supported New Delhi Streetkids Project. Later, visit Old Delhi, explore the spice markets, and visit Jama Masjid and Connaught Place.',
   3: u"Arrive in Jaipur and explore this gorgeous 'pink city'."}

   >>> # Create a new resource
   >>> booking = api.bookings.create({'currency': 'CAD', 'external_id': 'abc'})

   >>> # Modify an existing resource
   >>> booking.external_id = 'def'
   >>> booking.save()


Since `2.25.0 (2020-01-02)`_

.. code-block:: python

   >>> # since 2.25.0 reference stubs that fail to fetch will return a

   >>> # subclass of requests.HTTPError (See: https://github.com/gadventures/gapipy/pull/119)
   >>> # This can also be done on Query.get by passing a Falsy value for the
   >>> # httperrors_mapped_to_none kwarg.
   >>>
   >>> dep = api.departures.get('404_404', httperrors_mapped_to_none=None)
   ... # omitted stacktrace
   HTTPError: 404 Client Error: {"http_status_code":404,"message":"Not found.","errors":[],"time":"2020-01-02T19:46:07Z","error_id":"gapi_asdf1234"} for url: https://rest.gadventures.com/departures/404_404

   >>> dep = api.departures.get('404404')
   >>> dep.start_address.country
   <Country: BR (stub)>

   >>> # lets have GAPI return a _404_ error here for the country stub `fetch`
   >>> # when we attempt to retrieve the continent attribute

   >>> dep.start_address.country.continent  # reference/stub forces a fetch

   >>> # pre 2.25.0 behaviour
   ... # omitted stacktrace
   AttributeError: 'Country' has no field 'continent' available

   >>> # post 2.25.0 behaviour
   ... # omitted stacktrace
   HTTPError: 404 Client Error: {"http_status_code":404,"message":"Not found.","errors":[],"time":"2020-01-02T19:46:07Z","error_id":"gapi_qwer5678"} for url: https://rest.gadventures.com/countries/BR


Resources
---------

Resource objects are instantiated from python dictionaries created from JSON
data. The fields are parsed and converted to python objects as specified in the
resource class.

A nested resource will only be instantiated when its corresponding attribute is
accessed in the parent resource. These resources may be returned as a ``stub``,
and upon access of an attribute not present, will internally call ``.fetch()``
on the resource to populate it.

A field pointing to the URL for a collection of a child resources will hold a
``Query`` object for that resource. As for nested resources, it will only be
instantiated when it is first accessed.


Queries
-------

A Query for a resource can be used to fetch resources of that type (either a
single instance or an iterator over them, possibly filtered according to  some
conditions). Queries are roughly analogous to Django's QuerySets.

An API client instance has a query object for each available resource
(accessible by an attribute named after the resource name)


Methods on Query objects
========================

All queries support the ``get``, ``create`` and ``options`` methods. The other
methods are only supported for queries whose resources are listable.

``options()``
   Get the options for a single resource

``get(resource_id, [headers={}])``
   Get a single resource; optionally passing in a dictionary of header
   values.

``create(data)``
   Create an instance of the query resource using the given data.

``all([limit=n])``
   Generator over all resources in the current query. If ``limit`` is a
   positive integer ``n``, then only the first ``n`` results will be returned.

   * A ``TypeError`` will be raised if limit is not ``None`` or ``int`` type
   * A ``ValueError`` will be raised if ``limit <= 0``

``filter(field1=value1, [field2=value2, ...])``

``filter(**{"nested.field": "value"})``
   Filter resources on the provided fields and values. Calls to ``filter`` can
   be chained. The method will return a clone of the ``Query`` object and must
   be stored in a separate variable in order to have access to **stacked**
   filters.

``count()``
   Return the number of resources in the current query (by reading the
   ``count`` field on the response returned by requesting the list of
   resources in the current query).


Caching
-------

``gapipy`` can be configured to use a cache to avoid having to send HTTP
requests for resources it has already seen. Cache invalidation is not
automatically handled: it is recommended to listen to G API webhooks_ to purge
resources that are outdated.

.. _webhooks: https://developers.gadventures.com/docs/webhooks.html

By default, ``gapipy`` will use the cached data to instantiate a resource, but
a fresh copy can be fetched from the API by passing ``cached=False`` to
``Query.get``. This has the side-effect of recaching the resource with the
latest data, which makes this a convenient way to refresh cached data.

Caching can be configured through the ``cache_backend`` and ``cache_options``
settings. ``cached_backend`` should be a string of the fully qualified path to
a cache backend, i.e. a subclass of ``gapipy.cache.BaseCache``. A handful of
cache backends are available out of the box:

``gapipy.cache.SimpleCache``
   A simple in-memory cache for single process environments and is not
   thread safe.

``gapipy.cache.RedisCache``
   A key-value cache store using Redis as a backend.

``gapipy.cache.NullCache`` (Default)
   A cache that doesn't cache.

``gapipy.cache.DjangoCache`` (requires Django)
   A cache which uses Django's cache settings for configuration. Requires there
   be a ``gapi`` entry in ``settings.CACHES``.

Since the cache backend is defined by a python module path, you are free to use
a cache backend that is defined outside of this project.


Connection Pooling
------------------

We use the ``requests`` library, and you can take advantage of the provided
connection pooling options by passing in a ``'connection_pool_options'`` dict
to your client.

Values inside the ``'connection_pool_options'`` dict of interest are as
follows:

* Set ``enable`` to ``True`` to enable pooling. Defaults to ``False``.
* Use ``number`` to set the number of connection pools to cache.
  Defaults to 10.
* Use ``maxsize`` to set the max number of connections in each pool.
  Defaults to 10.
* Set ``block`` to ``True`` if the connection pool should block and wait
  for a connection to be released when it has reached ``maxsize``. If
  ``False`` and the pool is already at ``maxsize`` a new connection will
  be created without blocking, but it will not be saved once it is used.
  Defaults to ``False``.

See also:
---------

* http://www.python-requests.org/en/latest/api/#requests.adapters.HTTPAdapter
* http://urllib3.readthedocs.io/en/latest/reference/index.html#module-urllib3.connectionpool


Dependencies
------------

The only dependency needed to use the client is requests_.

.. _requests: http://python-requests.org


Testing
-------

Running tests is pretty simple. We use `nose` as the test runner. You can
install all requirements for testing with the following::

   $ pip install -r requirements-testing.txt

Once installed, run unit tests with::

   $ nosetests -A integration!=1

Otherwise, you'll want to include a GAPI Application Key so the integration
tests can successfully hit the API::

   $ export GAPI_APPLICATION_KEY=MY_SECRET_KEY; nosetests

In addition to running the test suite against your local Python interpreter, you
can run tests using `Tox <http://tox.testrun.org>`_. Tox allows the test suite
to be run against multiple environments, or in this case, multiple versions of
Python. Install and run the ``tox`` command from any place in the gapipy source
tree. You'll want to export your G API application key as well::

   $ export GAPI_APPLICATION_KEY=MY_SECRET_KEY
   $ pip install tox
   $ tox

Tox will attempt to run against all environments defined in the ``tox.ini``. It
is recommended to use a tool like `pyenv <https://github.com/yyuu/pyenv>`_ to
ensure you have multiple versions of Python available on your machine for Tox to
use.


Fields
------

* ``_model_fields`` represent dictionary fields.

.. note::

   * ``_model_fields = [('address', Address)]`` AND
   * ``Address`` subclasses ``BaseModel``

.. code-block:: python

   {
      "address": {
         "street": "19 Charlotte St",
         "city": "Toronto",
         "state": {
            "id": "CA-ON",
            "href": "https://rest.gadventures.com/states/CA-ON",
            "name": "Ontario"
         },
         "country": {
            "id": "CA",
            "href": "https://rest.gadventures.com/countries/CA",
            "name": "Canada"
         },
         "postal_zip": "M5V 2H5"
      }
   }


* ``_model_collection_fields`` represent a list of dictionary fields.

.. note::

   * ``_model_collection_fields = [('emails', AgencyEmail),]`` AND
   * ``AgencyEmail`` subclasses ``BaseModel``

.. code-block:: python

   {
      "emails": [
         {
            "type": "ALLOCATIONS_RELEASE",
            "address": "g@gadventures.com"
         },
         {
            "type": "ALLOCATIONS_RELEASE",
            "address": "g2@gadventures.com"
         }
      ]
   }

* ``_resource_fields`` refer to another ``Resource``




Contributing
============

.. note:: Ensure a Python 2 environment

0. Clone the project

   .. code-block:: sh

      $ git clone git@github.com:gadventures/gapipy


1. Run ``pip install -r requirements-dev.txt`` to setup dev dependencies.


2. Always make your changes in a branch and to submit a PR.

   .. code-block:: sh

      $ git checkout master
      $ git pull
      $ git checkout -b feature-branch-name
      $ git push origin feature-branch-name


3. Once the PR has been accepted/merged into the ``master`` branch, follow
   these steps.

   .. code-block:: sh

      $ cd /path/to/gapipy
      $ git checkout master
      $ git pull origin master


**Modify the following files:**

* Update **gapipy/__init__.py**

   * increment the ``__version__`` variable

   .. note::

      * style ``major.minor.patch``
      * update ``patch`` when adding new fields, fixing bugs introduced by a
        minor release.
      * update ``minor`` if there is some breaking change such as adding a new
        resource, removing fields, adding new behaviour.
      * update ``major`` when we switch to ``Python 3`` only support.
      * See `semver.org <https://semver.org>`_ for more information.

* Update **HISTORY.rst**

   * update this file with the new ``version`` & ``date``
   * Add some brief notes describing the changes.


4. Use ``make dist`` to check the generated long_description rST file is valid.

   .. note::

      * ignore ``warning: no previously-included files matching`` messages.
      * as long as you get a ``Checking dist/gapipy-a.b.c.tar.gz: PASSED``
        message, you are good!
      * If not, fix the errors as dictated in the output, and repeat.

   Example output when running ``make dist``:

   .. code-block:: sh

      $ make dist
      warning: no previously-included files matching '*' found under directory 'tests'
      warning: no previously-included files matching '__pycache__' found under directory '*'
      warning: no previously-included files matching '.eggs' found under directory '*'
      warning: no previously-included files matching '*.py[co]' found under directory '*'
      total 123
      -rw-r--r--  1 user  group  76276  5 Feb 02:53 gapipy-a.b.c.tar.gz
      Checking dist/gapipy-a.b.c.tar.gz: PASSED


5. Push the new *Release* commit

   * Use **Release a.b.c (YYYY-MM-DD)** format for the commit title. Optionally
     add a description that matches the changes made to **HISTORY.rst**.


6. Create a release on github with the following description (This will be
   tagged to the ``Release`` commit and not the PR/change commit)

   .. code-block:: md

      # Release a.b.c (YYYY-MM-DD)

      PR: #123

      A brief description describing the changes
      * bullet points
      * make for easy reading


7. Release!

      $ make release

Thanks for helping!
-------------------



History
=======

2.36.0 (2024-05-30)
-------------------

* Add ``contact_us`` field to the ``AgenchChain`` resource. This field can be
  ``None``, however should a value be present, it will be an object with three
  accessible attributes: ``email``, ``phone_number``, and ``website_url``. See
  the `PR #141`_ for more details.

.. _`PR #141`: https://github.com/gadventures/gapipy/pull/141


2.35.0 (2022-04-18)
-------------------

* Add new ``Client`` configuration value that will raise an error when an empty
  partial update (PATCH) payload is computed by gapipy. See `Issue #136`_ and
  the corresponding `PR #137`_ for more details.

* The new Client configuration kwarg is ``raise_on_empty_update``, whose
  default value is ``False``, and can also be set by passing it as an
  environment variable ``GAPI_CLIENT_RAISE_ON_EMPTY_UPDATE``. If this config
  value is set, then a call to ``Resource.save`` with ``partial=True`` will
  raise the new ``EmptyPartialUpdateError`` if an empty payload is computed.

  .. code-block:: python

    from gapipy import Client

    gapi = Client(application_key="your_api_key", raise_on_empty_update=True)
    departure_service = gapi.departure_services.get(123456)

    # we've changed nothing and are calling a partial save (PATCH)
    #
    # NOTE: the new EmptyPartialUpdateError will be raised here
    departure_service.save(partial=True)

.. _`Issue #136`: https://github.com/gadventures/gapipy/issues/136
.. _`PR #137`: https://github.com/gadventures/gapipy/pull/137


2.34.0 (2021-08-20)
-------------------

* Add ``travel_ready_policy`` model field to the ``Departure`` resource.
* More details can be found in our developer documentation.
  c.f. `Departure travel-ready-policy`_

.. _`Departure travel-ready-policy`: https://developers.gadventures.com/docs/departure.html#travel-ready-policy


2.33.0 (2021-07-06)
-------------------

* Add ``online_preferences`` field to the ``Agency Chain`` resource.


2.32.0 (2021-06-18)
-------------------

* Make ``future`` requirement more flexible. See `PR #134`_ for more details.

.. _`PR #134`: https://github.com/gadventures/gapipy/pull/134


2.31.1 (2021-05-14)
-------------------

* Initialize the ``DjangoCache`` via the ``BaseCache`` which exposes the
  ``default_timeout`` attribute to the class. Prior to this change, when using
  the ``DjangoCache``, items would persist forever as no timeout would be set
  on the entries. See `PR #133`_ for more details.

.. note:: ``DjangoCache`` was introduced in `2.30.0 (2021-02-08)`_

.. _`PR #133`: https://github.com/gadventures/gapipy/pull/133


2.31.0 (2021-03-02)
-------------------

* Introduce ``gapipy.constants`` module that holds common constants. See
  `PR #132`_ for more details.

* Reintroduce the ability to enable old behaviour (pre `2.25.0 (2020-01-02)`_)
  for ``Resource.fetch``. It adds an optional ``httperrors_mapped_to_none``
  parameter to the method (default ``None``), where if a list of HTTP Status
  codes is provided instead, will silently consume errors mapped to those
  status codes and return a ``None`` value instead of raising the HTTPError.
  See `PR #131`_ for more details.

.. _`PR #131`: https://github.com/gadventures/gapipy/pull/131
.. _`PR #132`: https://github.com/gadventures/gapipy/pull/132


2.30.1 (2021-02-08)
-------------------

* Fix for `2.30.0 (2021-02-08)`_ Adds a guard against configuring Django
  settings again as per the `Django settings docs`_. See `PR #130`_ for more
  details.

.. _`Django settings docs`: https://docs.djangoproject.com/en/3.1/topics/settings/#either-configure-or-django-settings-module-is-required
.. _`PR #130`: https://github.com/gadventures/gapipy/pull/130


2.30.0 (2021-02-08)
-------------------

* Adds a new cache backend; ``gapipy.cache.DjangoCache``. It requires ``Django``
  and a ``gapi`` entry in ``settings.CACHES``. See `PR #129`_ for more details.

.. _`PR #129`: https://github.com/gadventures/gapipy/pull/129/

**Usage:**

* Set the ``GAPI_CACHE_BACKEND`` Env varible to ``gapipy.cache.DjangoCache``.

OR

.. code-block:: python

   from gapipy import Client

   gapi = Client(
      application_key="live_your-secret-gapi-key",
      cache_backend="gapipy.cache.DjangoCache",
   )


2.29.0 (2021-02-05)
-------------------

* Adds ``Departure.relationships`` field via ``DepartureRelationship`` model
* Adds ``TourDossier.relationships`` field via ``TourDossierRelationship``
  model

.. warning:: BREAKING!

* Moves the ``gapipy.resources.tour.itinerary.ValidDuringRange`` class over to
  its own file ``gapipy.models.valid_duraing_range.ValidDuringRange``
  so that it can be reused by the ``TourDossierRelationship`` model. Any code
  importing the class directly will need to change the import path:

   .. code-block:: python

      # before
      from gapipy.resources.tour.itinerary.ValidDuringRange

      # now
      from gapipy.models import ValidDuringRange

* See `PR #128`_ for more details.

.. _`PR #128`: https://github.com/gadventures/gapipy/pull/128/


2.28.0 (2020-11-23)
-------------------

* Add a new ``Client`` config option, ``global_http_headers``, a dict of HTTP
  headers to add to each request made with that client.

  This is similar to the ``headers=`` kwargs available when making ``get`` and
  ``create`` calls, except that the ``global_http_headers`` set on a client
  will apply on *every request* made by that client instance.


2.27.0 (2020-05-26)
-------------------

.. warning:: BREAKING!

* Make ``Customer.nationality`` a *resource field*. This allows attribute style
  access to the field values, whereas before they needed to be accessed using
  dictionary accessor (``d["key"]``) syntax.

.. code-block:: python

   # before
   >>> api.customers.get(123456).nationality["name"]
   u'Canadian'

   # now
   >>> api.customers.get(123456).nationality.name
   u'Canadian'


2.26.4 (2020-04-28)
-------------------

* Fix `2.26.3 (2020-04-28) (Yanked)`_: Add missing ``CONTRIBUTING.rst`` to the
  manifest.

.. note:: Discovered when attempting to install ``gapipy`` via ``pip``.


2.26.3 (2020-04-28) (Yanked)
----------------------------

* Fix py2 & py3 compatibility for ``urlparse``


2.26.2 (2020-04-20)
-------------------

* Fix for `2.26.1 (2020-04-20)`_ and `Issue #113`_.

   * See `PR #125`_.
   * Remove the ``_set_resource_collection_field`` method in ``TourDossier``
   * Introducing the ``_Parent`` namedtuple in `PR #123`_.
     broke being able to Query-chain from Tour-Dossiers to departures
   * Buggy behaviour fixed from `2.26.1 (2020-04-20)`_

   .. code-block:: python

      >>> from gapipy import Client
      >>> api = Client(application_key='MY_SECRET_KEY')

      >>> api.tour_dossiers(24309).departures.count()
      # AttributeError: 'tuple' object has no attribute 'uri'

.. _`PR #125`: https://github.com/gadventures/gapipy/pull/125


2.26.1 (2020-04-20)
-------------------

* Fix for `2.26.0 (2020-04-14)`_ and `Issue #113`_.

   * Calls to ``APIRequestor.list_raw`` will use initialised its parameters,
     unless the URI provides its own.
   * See `PR #123`_.

* Add the ability to define the ``max_retries`` values on the requestor.

   * New ``env`` value ``GAPI_CLIENT_MAX_RETRIES``.
   * The default value will be ``0``, and if provided will override the ``retry``
     value on the ``requests.Session``.
   * This change will also always initialize a ``requests.Session`` value on
     initialisation of the ``gapipy.Client``.
   * See `PR #124`_.

* Add ``variation_id`` field to the ``Image`` resource.

   * See `Commit edc8d9b`_.

* Update the ``ActivityDossier`` and ``AccommodationDossier`` resources.

   * Remove the ``is_prepaid`` field.
   * Adds the ``has_costs`` field.
   * See `Commit bd35531`_. 

.. _`Issue #113`: https://github.com/gadventures/gapipy/issues/113
.. _`PR #123`: https://github.com/gadventures/gapipy/pull/123
.. _`PR #124`: https://github.com/gadventures/gapipy/pull/124
.. _`Commit edc8d9b`: https://github.com/gadventures/gapipy/commit/edc8d9b
.. _`Commit bd35531`: https://github.com/gadventures/gapipy/commit/bd35531


2.26.0 (2020-04-14)
-------------------

.. warning:: BREAKING!

* The ``Query.filter`` method will return a clone/copy of itself. This will
  preserve the state of ``filters`` on the original Query object.
* The ``Query.all`` method will **not** clear the filters after returning.
* The ``Query.all`` method will return a ``TypeError`` if a type other than
  an ``int`` is passed to the ``limit`` argument.
* The ``Query.count`` method will **not** clear the filters after returning.
* See `PR #121`_ for more details.

New behaviour with the ``Query.filter`` method:

.. code-block:: python

   >>> from gapipy import Client
   >>> api = Client(application_key='MY_SECRET_KEY')

   # create a filter on the departures
   >>> query = api.departures.filter(**{"tour_dossier.id": "24309"})
   >>> query.count()
   494

   # we preserve the filter status of the current query
   >>> query.filter(**{"availability.status": "AVAILABLE"}).count()
   80

   >>> query.count()
   494

* The ``AgencyChain.agencies`` attribute returns a list of ``Agency`` objects.
  See `Commit f34afd52`_.

.. _`PR #121`: https://github.com/gadventures/gapipy/pull/121
.. _`Commit f34afd52`: https://github.com/gadventures/gapipy/commit/f34afd52


2.25.1 (2020-01-02)
-------------------

* Improve contribution instructions to check long_description rST file in dist
* Dev Requirement updates:

   * Add ``readme_renderer==24.0``
   * Add ``twine==1.15.0`` for ``twine check`` command


2.25.0 (2020-01-02)
-------------------

* Failing to fetch inlined Resource (from Stubs) will raise the underlying
  requests.HTTPError instead of AttributeError resulting from a ``None``.
* Adds ``httperrors_mapped_to_none`` kwarg to ``gapipy.query.Query.get``
  with default value ``gapipy.query.HTTPERRORS_MAPPED_TO_NONE``
* Modifies ``gapipy.resources.base.Resource.fetch`` to
  pass ``httperrors_mapped_to_none=None`` to ``Query.get``
* This ensures that any underlying ``requests.HTTPError`` from ``Query.get``
  is bubbled up to the caller. It is most prevalent when reference Resource stubs
  fail to be retrieved from the G API. Prior to this change ``Resource.fetch``
  would return a ``None`` value resulting in an ``AttributeError``. Now, if the
  stub fails to fetch due to an HTTPError, that will be raised instead


2.24.3 (2019-12-12)
-------------------

* Exclude the ``tests`` package from the package distribution


2.24.2 (2019-12-12)
-------------------

* Adds the ``compute_request_signature`` and ``compute_webhook_validation_key``
  utility methods. See `PR #122`_.

.. _`PR #122`: https://github.com/gadventures/gapipy/pull/122


2.24.1 (2019-12-12)
-------------------

* Add ``slug`` field to ``TourDossier`` resource. See `PR #120`_.

.. _`PR #120`: https://github.com/gadventures/gapipy/pull/120


2.24.0 (2019-11-05)
-------------------

* Add missing/new fields to the following resources. See `PR #117`_.

   * AccommodationDossier: ``categories``, ``suggested_dossiers``, ``visited_countries``, ``visited_cities``
   * ActivityDossier: ``suggested_dossiers``, ``visited_countries``, ``visited_cities``
   * Departure: ``local_payments``
   * Itinerary: ``publish_state``

* Add ``continent`` and ``place`` references to the ``Countries`` resource. See
  `PR #115`_.
* Accept ``additional_headers`` optional kwarg on ``create``. See `PR #114`_.

.. _`PR #114`: https://github.com/gadventures/gapipy/pull/114
.. _`PR #115`: https://github.com/gadventures/gapipy/pull/115
.. _`PR #117`: https://github.com/gadventures/gapipy/pull/117


2.23.0 (2019-11-04)
-------------------

* Remove deprecated ``tour_dossiers.itineraries`` field and related code


2.22.0 (2019-10-10)
-------------------

* Add ``booking_company`` field to ``Booking`` resource


2.21.0 (2019-04-09)
-------------------

* Add ``ripple_score`` to ``Itinerary`` resource


2.20.1 (2019-02-20)
-------------------

* HISTORY.rst doc fixes


2.20.0 (2019-02-20)
-------------------

* Add ``Requirement`` and ``RequirementSet`` resources
* Move ``Checkin`` resource to the ``resources.booking`` module
* The ``Query`` object will resolve to use the ``href`` value when
  returning the iterator to fetch ``all`` of some resource. This is
  needed because ``bookings/123456/requirements`` actually returns a list
  of ``RequirementSet`` resources
* See `Release tag 2.20.0`_ for more details.

.. _`Release tag 2.20.0`: https://github.com/gadventures/gapipy/releases/tag/2.20.0


2.19.4 (2019-02-14)
-------------------

* Add ``get_category_name`` helper method to ``TourDossier`` resource


2.19.3 (2019-02-12)
-------------------

* Attempt to fix rST formatting of ``README`` and ``HISTORY`` on pypi


2.19.2 (2019-02-12)
-------------------

* Become agnostic between redis ``2.x.x`` && ``3.x.x`` versions

   * the ``setex`` method argument order changes between the major versions


2.19.1 (2019-02-12)
-------------------

.. note:: HotFix for `2.19.0 (2019-02-12)`_.

* adds ``requirements.txt`` file to the distribution ``MANIFEST``


2.19.0 (2019-02-12)
-------------------

* Add ``booking_companies`` field to ``Itinerary`` resource
* Pin our requirement/dependency versions

   * pin ``future == 0.16.0``
   * pin ``requests >= 2.18.4, < 3.0.0``
   * read ``setup.py`` requirements from ``requirements.txt``


2.18.1 (2019-02-07)
-------------------

* Add ``customers`` nested resource to ``bookings``


2.18.0 (2018-12-14)
-------------------

* Add ``merchandise`` resource
* Add ``merchandise_services`` resources


2.17.0 (2018-11-12)
-------------------

* Add ``membership_programs`` field to the ``Customer`` resource


2.16.0 (2018-11-07)
-------------------

* Completely remove the deprecated ``add_ons`` field from the Departure resource
* Add missing fields to various Dossier resources

   * AccommodationDossier: ``flags``, ``is_prepaid``, ``service_time``, ``show_on_reservation_sheet``
   * ActivityDossier: ``is_prepaid``, ``service_time``, ``show_on_reservation_sheet``
   * CountryDossier: ``flags``
   * PlaceDossier: ``flags``
   * TransportDossier: ``flags``

* Add ``valid_during_ranges`` list field to the Itinerary resource. This field is
  a list field of the newly added ``ValidDuringRange`` model (described below)
* Add ``ValidDuringRange`` model. It consists of two date fields, ``start_date``,
  and ``end_date``. It also provides a number of convenience methods to determine
  if the date range provided is valid, or relative to some date.

   * ``is_expired``: Is it expired relative to ``datetime.date.today``
   * ``is_valid_today``: Is it valid relative to ``datetime.date.today``
   * ``is_valid_during_range``: Is it valid for some give start/end date range
   * ``is_valid_on_or_after_date``: Is it valid on or after some date
   * ``is_valid_on_or_before_date``: Is it valid on or before some date
   * ``is_valid_on_date``: Is it valid on some date
   * ``is_valid_sometime``: Is it valid at all


2.15.0 (2018-10-10)
-------------------

* Add ``country`` reference to ``Nationality`` resource.
* Moved ``resources/bookings/nationality.py`` to ``resources/geo/*``.


2.14.6 (2018-08-01)
-------------------

* Check for presence of ``id`` field directly in the Resource ``__dict__`` in
  order to prevent a chicken/egg situation when attempting to ``save``. This is
  needed due to the change introduced in 2.14.4, where we explicitly raise an
  AttributeError when trying to access the ``id`` attribute.
* Added ``service_code`` field for Activty & Accommodation Dossier resources.


2.14.5 (2018-08-01)
-------------------

* deleted


2.14.4 (2018-07-13)
-------------------

* Raise an ``AttributeError`` when trying to access ``id`` on
  ``Resource.__getattr__``.
* Don't send duplicate params when paginating through list results.
* Implement ``first()`` method for ``Query``.

2.14.3 (2018-05-29)
-------------------

* Expose Linked Bookings via the API.

2.14.1 (2018-05-15)
-------------------

* Add ``booking_companies`` field to Agency resource.
* Remove ``bookings`` field from Agency resource.
* Add ``requirements`` as_is field to Departure Service resource.
* Add ``policy_emergency_phone_number`` field to Insurance Service resource.


2.14.0 (2018-05-15)
-------------------

* Remove deprecated ``add_ons`` field from ``Departure`` resource.
* Add ``costs`` field to ``Accommodation`` & ``ActivityDossier`` resources.


2.13.0 (2018-03-31)
-------------------

* Add ``meal_budgets`` list field to ``CountryDossier`` resource.
* Add ``publish_state`` field to ``DossierFeatures`` resource.


2.12.0 (2018-02-14)
-------------------

* Add optional ``headers`` parameter to Query.get to allow HTTP-Headers to be
  passed. e.g. ``client.<resource>.get(1234, headers={'A':'a'})``. See
  `PR #91`_.
* Add ``preferred_display_name`` field to ``Agency`` resource. See `PR #92`_.
* Add ``booking_companies`` array field to all Product-type resources. See
  `PR #93`_.

   * Accommodation
   * Activity
   * AgencyChain
   * Departure
   * SingleSupplement
   * TourDossier
   * Transport

.. _`PR #91`: https://github.com/gadventures/gapipy/pull/91
.. _`PR #92`: https://github.com/gadventures/gapipy/pull/92
.. _`PR #93`: https://github.com/gadventures/gapipy/pull/93


2.11.4 (2018-01-29)
-------------------

* Add ``agency_chain`` field to ``Booking`` resource
* Add ``id`` field as part of the ``DossierDetail`` model See `PR #89`_.
* Add ``agency_chains`` field to the ``Agency`` resource. See `PR #90`_.
* See `Release tag 2.11.3`_ for more details.

.. _`PR #89`: https://github.com/gadventures/gapipy/pull/89
.. _`PR #90`: https://github.com/gadventures/gapipy/pull/90
.. _`Release tag 2.11.3`: https://github.com/gadventures/gapipy/releases/tag/2.11.3


2.11.0 (2017-12-18)
-------------------

* The ``Customer.address`` field uses the ``Address`` model, and is no longer a
  dict.
* Passing in ``uuid=True`` to ``Client`` kwargs enables ``uuid`` generation
  for every request.


2.10.0 (2017-12-01)
-------------------

* Add the ``amount_pending`` field to the ``Booking`` resource
* The ``PricePromotion`` model extends from the ``Promotion`` resource (PR/85)
* Update the ``Agent`` class to use BaseModel classes for the ``role``
  and ``phone_numbers`` fields.
* see `Release tag 2.10.0`_ for more details.

.. _`Release tag 2.10.0`: https://github.com/gadventures/gapipy/releases/tag/2.10.0


2.9.3 (2017-11-23)
------------------

.. note:: We have skipped Release ``2.9.2`` due to pypi upload issues.

* Expose ``requirement_set`` for ``departure_services`` & ``activity_services``.


2.9.1 (2017-11-22)
------------------

.. note:: * We have skipped Release ``2.9.0`` due to pypi upload issues.

* Adds the ``options`` method on the Resource Query object. See
  `Release tag 2.9.1`_ for more details.

.. _`Release tag 2.9.1`: https://github.com/gadventures/gapipy/releases/tag/2.9.1


2.8.2 (2017-11-14)
------------------

* Adds fields ``sale_start_datetime`` and ``sale_finish_datetime`` to the
  Promotion resource. The fields mark the start/finish date-time values
  for when a Promotion is applicable. The values represented are in UTC.


2.8.1 (2017-10-25)
------------------

* Add new fields to the ``Agency`` and ``AgencyChain`` resources


2.8.0 (2017-10-23)
------------------

* This release adds a behaviour change to the ``.all()`` method on resource
  Query objects. Prior to this release, the base Resource Query object would
  retain any previously added ``filter`` values, and be used in subsequent
  calls. Now the underlying filters are reset after a ``<resource>.all()`` call
  is made.

  See `Issue #76`_ and `PR #77`_ for details and the resulting fix. 

* Adds missing fields to the Agency and Flight Service resources (PR/78)

.. _`Issue #76`: https://github.com/gadventures/gapipy/issues/76
.. _`PR #77`: https://github.com/gadventures/gapipy/pull/77


2.7.6 (2017-10-04)
------------------

* Add ``agency`` field to ``Booking`` resource.


2.7.5 (2017-09-25)
------------------

* Add test fix for Accommodation. It is a listable resource as of ``2.7.4``
* Add regression test for departures.addon.product model
  * Ensure Addon's are instantiated to the correct underlying model.
  * Prior to this release, all Addon.product resources were instantiated as
  ``Accommodation``.


2.7.4 (2017-09-20)
------------------

* Add ``videos``, ``images``, and ``categories`` to ``Activity``, ``Transport``,
  ``Place``, and ``Accommodation Dossier`` resources.
* Add ``flags`` to Itinerary resource
* Add list view of ``Accommodations`` resource


2.7.3 (2017-09-06)
------------------

* Add ``type`` field to ``AgencyDocument`` model
* Add ``structured_itinerary`` model collection field to ``Departure`` resource


2.7.2 (2017-08-18)
------------------

* Fix flight_status Reference value in FlightService resource


2.7.1 (2017-08-18)
------------------

* Fix: remove FlightStatus import reference for FlightService resource
* Add fields (fixes two broken Resource tests)

  * Add ``href`` field for ``checkins`` resource
  * Add ``date_cancelled`` field for ``departures`` resource

* Fix broken ``UpdateCreateResource`` tests


2.7.0 (2017-08-18)
------------------

* Remove ``flight_statuses`` and ``flight_segments`` resources.


2.6.2 (2017-08-11)
------------------

* Version bump


2.6.1 (2017-08-11)
------------------

* Adds a Deprecation warning when using the ``tours`` resource.


2.6.0 (2017-08-11)
------------------

* Fixed `Issue #65`_: only
  write data into the local cache after a fetch from the API, do not write data
  into the local cache when fetching from the local cache.

.. _`Issue #65`: https://github.com/gadventures/gapipy/issues/65


2.5.2 (2017-04-26)
------------------

* Added ``future`` dependency to setup.py


2.5.1 (2017-02-08)
------------------

* Fixed an issue in which modifying a nested dictionary caused gapipy to not
  identify a change in the data.
* Added ``tox.ini`` for testing across Python platforms.
* Capture ``403`` Status Codes as a ``None`` object.

2.5.0 (2017-01-20)
------------------

* Provided Python 3 functionality (still Python 2 compatible)
* Removed Python 2 only tests
* Installed ``future`` module for smooth Python 2 to Python 3 migration
* Remove ``DictToModel`` class and the associated tests
* Add ``Dossier`` Resource(s)
* Minor field updates to: ``Customer``, ``InsuranceService``,
  ``DepartureService``, ``Booking``, ``FlightStatus``, ``State``


2.4.9 (2016-11-22)
------------------

* Fixed a bug with internal ``_get_uri`` function.


2.4.8 (2016-11-11)
------------------

* Adjusted ``Checkin`` resource to meet updated spec.


2.4.7 (2016-10-25)
------------------

* Added ``Checkin`` resource.


2.4.6 (2016-10-19)
------------------

* Fix broken ``Duration`` init in ``ActivityDossier`` (likely broke due to
  changes that happened in 2.0.0)


2.4.5 (2016-10-13)
------------------

* Added ``Image`` resource definition and put it to use in ``Itinerary`` and,
  ``PlaceDossier``


2.4.4 (2016-09-09)
------------------

* Added ``date_last_modified`` and ``date_created`` to ``Promotion``.


2.4.3 (2016-09-06)
------------------

* Added ``gender`` to ``Customer``.
* Added ``places_of_interest`` to ``Place``.


2.4.2 (2016-07-08)
------------------

* Added ``departure`` reference to ``DepartureComponent``


2.4.1 (2016-07-06)
------------------

* Removed use of ``.iteritems`` wherever present in favour of ``.items``
* Added ``features`` representation to ``ActivityDossier`` and,
  ``TransportDossier``


2.4.0 (2016-06-29)
------------------

* Added ``CountryDossier`` resource.


2.3.0 (2016-06-28)
------------------

* Added ``DossierSegment`` resource.
* Added ``ServiceLevel`` resource.


2.2.2 (2016-06-08)
------------------

* Added day ``label`` field to the ``Itinerary`` resource.


2.2.1 (2016-06-06)
------------------

* Added ``audience`` field to the ``Document`` resource.


2.2.0 (2016-05-17)
------------------

* Added ``transactional_email``, and ``emails`` to ``Agency`` resource.


2.1.2 (2016-05-17)
------------------

* Added ``audience`` to ``Invoice`` resource.


2.1.1 (2016-04-29)
------------------

* Removed invalid field, ``email`` from ``AgencyChain``


2.1.0 (2016-04-25)
------------------

* Added new resource, ``AgencyChain``


2.0.0 (2016-03-11)
------------------

The global reference to the last instantiated ``Client`` has been removed. It
is now mandatory to pass in a Client instance when instantiating a ``Model`` or
``Resource``.

In practice, this should not introduce too many changes in codebases that are
using ``gapipy``, since most resource interacation happens through a ``Client``
instance (e.g. ``api.tours.get(123)``, or ``api.customers.create({...})``),
instead of being instantiated independently. The one possible exception is unit
testing: in that case, ``Client.build`` can be useful.

The global variable was causing issues with connection pooling when multiple
client with different configurations were used at the same time.


1.1.0 (2016-03-11)
------------------

* Added new resource, ``DossierFeature``


1.0.0 (2016-02-29)
------------------

* Adopted `Semantic Versioning`_ for this project.

.. warning:: BREAKING!

* Refactored how the cache key is set. This is a breaking change for any
  modules that implemented their own cache interface. The cache modules are
  no longer responsible for defining the cache value, but simply storing
  whatever it is given into cache. The ``Query`` object now introduces a
  ``query_key`` method which generates the cache key sent to the cache
  modules.

.. _`Semantic Versioning`: http://semver.org/


0.6.3 (2016-01-21)
------------------

* Added better error handling to ``Client.build``. An AttributeError raised when
  instantiating a resource won't be shadowed by the except block anymore.


0.6.2 (2016-01-20)
------------------

* Fixed a regression bug when initializing DepartureServiceRoom model.


0.6.1 (2016-01-20)
------------------

* Fixed a regression bug when initializing services.


0.6.0 (2016-01-20)
------------------

* Fixed a bug when initializing list of resources.


0.5.5 (2016-01-08)
------------------

* Added a component of type ``ACCOMMODATION`` to ``Itineraries``.


0.5.4 (2016-01-04)
------------------

* Added ``associated_services`` to ``SingleSupplementService``


0.5.3 (2015-12-31)
------------------

* Added ``name`` to ``Departure``.
* Happy New Year!


0.5.2 (2015-12-15)
------------------

* Added ``variation_id`` to ``BaseCache`` to fix a ``TypeError`` when using
  the ``NullCache``


0.5.1 (2015-12-14)
------------------

* Add ``associated_agency`` to ``bookings`` resource


0.5.0 (2015-12-10)
------------------

* Minor adjusted in Query internals to ensure the ``variation_id`` of an
  Itinerary is handled properly.
* Added ``ItineraryHighlights`` and ``ItineraryMedia`` resources. These are
  sub resources of the ``Itinerary``


0.4.6 (2015-12-09)
------------------

* Added connection pool caching to ``RedisCache``. Instances of ``gapipy`` with
  the same cache settings (in the same Python process) will share a connection
  pool.


0.4.5 (2015-11-05)
------------------

* Added ``code`` field to the ``type`` of an ``Itinerary``'s listed
  ``details``.


0.4.4 (2015-11-04)
------------------

* Added the ``details`` field to the ``Itinerary`` resource -- a list of
  textual details about an itinerary.


0.4.3 (2015-11-03)
-------------------

* Added the ``tour_dossier`` field to the ``Itinerary`` resource.


0.4.2 (2015-10-28)
------------------

* Fixed a bug that would cause ``amount`` when looking at ``Promotion`` objects
  in the ``Departure`` to be removed from the data dict.


0.4.1 (2015-10-16)
------------------

* Moved an import of ``requests`` down from the module level. Fixes issues in
  CI environments.


0.4.0 (2015-10-13)
------------------

* Added connection pooling options, see docs for details on
  ``connection_pool_options``.


0.3.0 (2015-09-24)
------------------

* Modified how the ``Promotion`` object is loaded within ``price_bands`` on a
  ``Departure``. It now correctly captures the ``amount`` field.


0.2.0 (2015-09-15)
------------------

* Modified objects within ``cache`` module to handle ``variation_id``, which is
  exposed within the ``Itinerary`` object. Previously, the ``Itinerary`` would
  not be correctly stored in cache with its variant reference.


0.1.51 (2015-08-31)
-------------------

* Added the ``components`` field to the ``Departure`` resource.


0.1.50 (2015-07-28)
-------------------

* Fixed an issue with the default ``gapipy.cache.NullCache`` when ``is_cached``
  was used.


0.1.49 (2015-07-23)
-------------------

* Added new fields to ``Itinerary`` revolving around variations.
* Added ``declined_reason`` to all service resources.


0.1.48 (2015-07-15)
-------------------

* Add DeclinedReason resource


0.1.47 (2015-07-08)
-------------------

* Fixed a bug in ``APIRequestor.get``. Requesting a resource with with an id of
  ``0`` won't raise an Exception anymore.


0.1.46 (2015-06-10)
-------------------

* Added ``associated_services`` and ``original_departure_service`` to various
  service resources and ``departure_services`` model respectively.


0.1.45 (2015-05-27)
-------------------

* Fixed ``products`` within the ``Promotion`` resource to properly retain
  ``type`` and ``sub_type`` fields after being parsed into a dictionary.


0.1.44 (2015-05-22)
-------------------

* Changed default ``cache_backend`` to use ``gapipy.cache.NullCache``.
  Previously, ``SimpleCache`` was the default and led to confusion in
  production environments, specifically as to why resources were not matching
  the API output. Now, by default, to get any caching from gapipy you must
  explicitly set it.


0.1.43 (2015-04-29)
-------------------

* Fixed ``Place`` init with empty admin_divisions.


0.1.42 (2015-04-29)
-------------------

* Added ``description`` to ``TourCategory`` resource.


0.1.41 (2015-04-14)
-------------------

* Added ``DepartureComponent`` resource. See the official G API
  `documentation <https://developers.gadventures.com/docs/departure_component.html>`_
  for details.


0.1.40 (2015-04-06)
-------------------

* Added ``deposit`` to ``DepartureService`` resource.


0.1.39 (2015-03-31)
-------------------

* Refactor ``APIRequestor._request``. While this should not change existing
  functionality, it is now possible to override specific methods on the class.


0.1.38 (2015-03-23)
-------------------

* Fixed: Due to inconsistencies in the G API with regards to nested resources,
  the ``fetch`` function was modified to use the raw data from the API, rather
  than a specific set of allowed fields.


0.1.37 (2015-03-23)
-------------------

* Fixed: Iterating over ``products`` within the ``promotions`` object now works
  as expected. Previously, accessing the ``products`` attribute would result in
  a Query object with incorrect parameters.


0.1.36 (2015-03-17)
-------------------

* Support free to amount price range formatting (e.g. Free-10CAD)


0.1.35 (2015-03-12)
-------------------

* Added ``duration_min`` & ``duration_max`` to ``ActivityDossier`` model


0.1.34 (2015-03-11)
-------------------

* Added ``OptionalActivity`` model
* All Dossiers with ``details``:
  * Now represented as list of ``DossierDetail`` models
  * Added convenience methods for retrieving specific details
* ``ItineraryComponent`` and ``ActivityDossier`` use new ``Duration`` model
  for their ``duration`` field/property
* Added ``duration_label`` and ``location_label`` to ``ItineraryComponent``
* Added ``duration_label``, ``price_per_person_label``, and
  ``price_per_group_label`` to ``ActivityDossier``


0.1.33 (2015-03-02)
-------------------

* Added ``name`` field to the Itinerary resource.


0.1.32 (2015-02-18)
-------------------

* Changed cache key creation to account for ``GAPI_LANGUAGE`` when the
  environment variable is set.


0.1.31 (2015-02-18)
-------------------

* Fixed a bug when setting _resource_fields in ``DepartureService`` resource


0.1.30 (2015-02-11)
-------------------

* ``TourDossier.structured_itineraries`` now refers to a list of Itinerary
  resources


0.1.29 (2015-02-10)
-------------------

* Added ``TransportDossier`` and ``Itinerary`` resources.

* The reference to the itinerary in a ``DepartureService`` is now a
  full-fledged ``Itinerary`` resource.


0.1.28 (2015-01-22)
-------------------

* Bug fix to correctly send ``Content-Type: application/json`` in POST, PUT,
  or PATCH.


0.1.27 (2015-01-19)
-------------------

* Update ``DepartureService`` object to contain a reference to its
  ``Itinerary``


0.1.26 (2015-01-14)
-------------------

* Normalize API request headers, to promote caching.


0.1.25 (2015-01-09)
-------------------

* Added ``ActivityDossier`` and ``AccommodationDossier`` resources, as well as
  references to it from ``Activity`` and ``Accommodation``.


0.1.24 (2015-01-07)
-------------------

* Added ``PlaceDossier`` resource, as well as reference to it from ``Place``


0.1.22 (2014-12-12)
-------------------

* Added ``advertised_departures`` to ``TourDossier``


0.1.21 (2014-11-26)
-------------------

* Fixed a bug with promotions on a Price object. When promotions were accessed,
  gapipy would query for all promotions, rather than returning the inline list.


0.1.20 (2014-11-20)
-------------------

* Departure resource is now listable via filters.


0.1.19 (2014-11-17)
-------------------

* Fixed a bug with ``RedisCache`.is_cached` where it would not use the set
  ``key_prefix`` when checking for existence in cache. Effectively, it would
  always return False


0.1.18 (2014-11-12)
-------------------

* When setting a ``date_field``, initiate it as a ``datetime.date`` type.


0.1.17 (2014-11-07)
-------------------

* Deprecated ``RedisHashCache`` from cache backends available by default. Was not
  well tested or reliable.


0.1.16 (2014-10-28)
---------------------

* Fixed a bug where if a model field received ``null`` as a value, it would fail.
  Now, if the result is ``null``, the model field will have an appropriate ``None``
  value.


0.1.15 (2014-10-23)
-------------------

* Fix a bug in the DepartureRoom model. The ``price_bands`` attribute is now
  properly set.


0.1.14 (2014-10-22)
-------------------

* Fixed a bug where AgencyDocument was not included in the code base.


0.1.13 (2014-10-21)
-------------------

* Add ``latitude``, ``longitude``, and ``documents`` to the ``Agency``
  resource.


0.1.12 (2014-10-20)
-------------------

* ``date_created`` on the ``Agency`` resource is correctly parsed as a local
  time.


0.1.11 (2014-10-15)
-------------------

* Improve the performance of ``Resource.fetch`` by handling cache get/set.


0.1.10 (2014-10-09)
-------------------

* Fix a bug in AccommodationRoom price bands. The ``season_dates`` and
  ``blackout_dates`` attributes are now properly set.


0.1.9 (2014-09-23)
------------------

* Add `iso_639_3` and `iso_639_1` to ``Language``


0.1.8 (2014-09-17)
------------------

* Remove the ``add_ons`` field in ``Departure``, and add ``addons``.


0.1.7 (2014-08-22)
------------------

* Fix a bug when initializing AccommodationRoom from cached data.


0.1.6 (2014-08-19)
------------------

* Add Query.purge_cached


0.1.5 (2014-07-29)
------------------

* Add ``details`` field to the list of ``incomplete_requirements`` in a
  ``DepartureService``.


0.1.4 (2014-07-21)
------------------

* Removed sending of header `X-HTTP-Method-Override: PATCH` when the update
  command is called. Now, when `.save(partial=True)` is called, the
  correct PATCH HTTP method will be sent with the request.


0.1.3 (2014-07-18)
------------------

* Return ``None`` instead of raising a HTTPError 404 exception when fetching a
  non-existing resource by id.
* Added ability to create resources from the Query objects on the client
  instance.

.. code-block:: python

   obj = {'name': {'legal_first_name': 'Pat', ...}, ...}
   api.customers.create(obj)


0.1.2 (2014-07-14)
------------------

* Added Query.is_cached
* Added cache options


0.1.1 (2014-06-27)
------------------

* Use setuptools find_packages


0.1.0 (2014-06-20)
------------------

* First release on PyPI.
            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/gadventures/gapipy",
    "name": "gapipy",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "gapipy",
    "author": "G Adventures",
    "author_email": "software@gadventures.com",
    "download_url": "https://files.pythonhosted.org/packages/f6/a3/c0094cfbe535e778c6383322da614da1cab53bd406ad176e7f7f67d07456/gapipy-2.36.0.tar.gz",
    "platform": null,
    "description": "G API Python Client\n===================\n\n.. image:: https://badge.fury.io/py/gapipy.svg\n    :target: http://badge.fury.io/py/gapipy\n\nA client for the G Adventures REST API (https://developers.gadventures.com)\n\n* GitHub Repository: https://github.com/gadventures/gapipy/\n* Documentation: http://gapipy.readthedocs.org.\n* Free software: MIT License\n\n\nQuick Start\n-----------\n\n.. code-block:: python\n\n   >>> from gapipy import Client\n   >>> api = Client(application_key='MY_SECRET_KEY')\n\n   >>> # Get a resource by id\n   >>> tour_dossier = api.tour_dossiers.get(24309)\n   >>> tour_dossier.product_line\n   u'AHEH'\n   >>> tour_dossier.departures.count()\n   134\n   >>> tour_dossier.name\n   u'Essential India'\n   >>> itinerary = tour_dossier.structured_itineraries[0]\n   >>> {day.day: day.summary for day in itinerary.days[:3]}\n   {1: u'Arrive at any time. Arrival transfer included through the G Adventures-supported Women on Wheels project.',\n   2: u'Take a morning walk through the city with a young adult from the G Adventures-supported New Delhi Streetkids Project. Later, visit Old Delhi, explore the spice markets, and visit Jama Masjid and Connaught Place.',\n   3: u\"Arrive in Jaipur and explore this gorgeous 'pink city'.\"}\n\n   >>> # Create a new resource\n   >>> booking = api.bookings.create({'currency': 'CAD', 'external_id': 'abc'})\n\n   >>> # Modify an existing resource\n   >>> booking.external_id = 'def'\n   >>> booking.save()\n\n\nSince `2.25.0 (2020-01-02)`_\n\n.. code-block:: python\n\n   >>> # since 2.25.0 reference stubs that fail to fetch will return a\n\n   >>> # subclass of requests.HTTPError (See: https://github.com/gadventures/gapipy/pull/119)\n   >>> # This can also be done on Query.get by passing a Falsy value for the\n   >>> # httperrors_mapped_to_none kwarg.\n   >>>\n   >>> dep = api.departures.get('404_404', httperrors_mapped_to_none=None)\n   ... # omitted stacktrace\n   HTTPError: 404 Client Error: {\"http_status_code\":404,\"message\":\"Not found.\",\"errors\":[],\"time\":\"2020-01-02T19:46:07Z\",\"error_id\":\"gapi_asdf1234\"} for url: https://rest.gadventures.com/departures/404_404\n\n   >>> dep = api.departures.get('404404')\n   >>> dep.start_address.country\n   <Country: BR (stub)>\n\n   >>> # lets have GAPI return a _404_ error here for the country stub `fetch`\n   >>> # when we attempt to retrieve the continent attribute\n\n   >>> dep.start_address.country.continent  # reference/stub forces a fetch\n\n   >>> # pre 2.25.0 behaviour\n   ... # omitted stacktrace\n   AttributeError: 'Country' has no field 'continent' available\n\n   >>> # post 2.25.0 behaviour\n   ... # omitted stacktrace\n   HTTPError: 404 Client Error: {\"http_status_code\":404,\"message\":\"Not found.\",\"errors\":[],\"time\":\"2020-01-02T19:46:07Z\",\"error_id\":\"gapi_qwer5678\"} for url: https://rest.gadventures.com/countries/BR\n\n\nResources\n---------\n\nResource objects are instantiated from python dictionaries created from JSON\ndata. The fields are parsed and converted to python objects as specified in the\nresource class.\n\nA nested resource will only be instantiated when its corresponding attribute is\naccessed in the parent resource. These resources may be returned as a ``stub``,\nand upon access of an attribute not present, will internally call ``.fetch()``\non the resource to populate it.\n\nA field pointing to the URL for a collection of a child resources will hold a\n``Query`` object for that resource. As for nested resources, it will only be\ninstantiated when it is first accessed.\n\n\nQueries\n-------\n\nA Query for a resource can be used to fetch resources of that type (either a\nsingle instance or an iterator over them, possibly filtered according to  some\nconditions). Queries are roughly analogous to Django's QuerySets.\n\nAn API client instance has a query object for each available resource\n(accessible by an attribute named after the resource name)\n\n\nMethods on Query objects\n========================\n\nAll queries support the ``get``, ``create`` and ``options`` methods. The other\nmethods are only supported for queries whose resources are listable.\n\n``options()``\n   Get the options for a single resource\n\n``get(resource_id, [headers={}])``\n   Get a single resource; optionally passing in a dictionary of header\n   values.\n\n``create(data)``\n   Create an instance of the query resource using the given data.\n\n``all([limit=n])``\n   Generator over all resources in the current query. If ``limit`` is a\n   positive integer ``n``, then only the first ``n`` results will be returned.\n\n   * A ``TypeError`` will be raised if limit is not ``None`` or ``int`` type\n   * A ``ValueError`` will be raised if ``limit <= 0``\n\n``filter(field1=value1, [field2=value2, ...])``\n\n``filter(**{\"nested.field\": \"value\"})``\n   Filter resources on the provided fields and values. Calls to ``filter`` can\n   be chained. The method will return a clone of the ``Query`` object and must\n   be stored in a separate variable in order to have access to **stacked**\n   filters.\n\n``count()``\n   Return the number of resources in the current query (by reading the\n   ``count`` field on the response returned by requesting the list of\n   resources in the current query).\n\n\nCaching\n-------\n\n``gapipy`` can be configured to use a cache to avoid having to send HTTP\nrequests for resources it has already seen. Cache invalidation is not\nautomatically handled: it is recommended to listen to G API webhooks_ to purge\nresources that are outdated.\n\n.. _webhooks: https://developers.gadventures.com/docs/webhooks.html\n\nBy default, ``gapipy`` will use the cached data to instantiate a resource, but\na fresh copy can be fetched from the API by passing ``cached=False`` to\n``Query.get``. This has the side-effect of recaching the resource with the\nlatest data, which makes this a convenient way to refresh cached data.\n\nCaching can be configured through the ``cache_backend`` and ``cache_options``\nsettings. ``cached_backend`` should be a string of the fully qualified path to\na cache backend, i.e. a subclass of ``gapipy.cache.BaseCache``. A handful of\ncache backends are available out of the box:\n\n``gapipy.cache.SimpleCache``\n   A simple in-memory cache for single process environments and is not\n   thread safe.\n\n``gapipy.cache.RedisCache``\n   A key-value cache store using Redis as a backend.\n\n``gapipy.cache.NullCache`` (Default)\n   A cache that doesn't cache.\n\n``gapipy.cache.DjangoCache`` (requires Django)\n   A cache which uses Django's cache settings for configuration. Requires there\n   be a ``gapi`` entry in ``settings.CACHES``.\n\nSince the cache backend is defined by a python module path, you are free to use\na cache backend that is defined outside of this project.\n\n\nConnection Pooling\n------------------\n\nWe use the ``requests`` library, and you can take advantage of the provided\nconnection pooling options by passing in a ``'connection_pool_options'`` dict\nto your client.\n\nValues inside the ``'connection_pool_options'`` dict of interest are as\nfollows:\n\n* Set ``enable`` to ``True`` to enable pooling. Defaults to ``False``.\n* Use ``number`` to set the number of connection pools to cache.\n  Defaults to 10.\n* Use ``maxsize`` to set the max number of connections in each pool.\n  Defaults to 10.\n* Set ``block`` to ``True`` if the connection pool should block and wait\n  for a connection to be released when it has reached ``maxsize``. If\n  ``False`` and the pool is already at ``maxsize`` a new connection will\n  be created without blocking, but it will not be saved once it is used.\n  Defaults to ``False``.\n\nSee also:\n---------\n\n* http://www.python-requests.org/en/latest/api/#requests.adapters.HTTPAdapter\n* http://urllib3.readthedocs.io/en/latest/reference/index.html#module-urllib3.connectionpool\n\n\nDependencies\n------------\n\nThe only dependency needed to use the client is requests_.\n\n.. _requests: http://python-requests.org\n\n\nTesting\n-------\n\nRunning tests is pretty simple. We use `nose` as the test runner. You can\ninstall all requirements for testing with the following::\n\n   $ pip install -r requirements-testing.txt\n\nOnce installed, run unit tests with::\n\n   $ nosetests -A integration!=1\n\nOtherwise, you'll want to include a GAPI Application Key so the integration\ntests can successfully hit the API::\n\n   $ export GAPI_APPLICATION_KEY=MY_SECRET_KEY; nosetests\n\nIn addition to running the test suite against your local Python interpreter, you\ncan run tests using `Tox <http://tox.testrun.org>`_. Tox allows the test suite\nto be run against multiple environments, or in this case, multiple versions of\nPython. Install and run the ``tox`` command from any place in the gapipy source\ntree. You'll want to export your G API application key as well::\n\n   $ export GAPI_APPLICATION_KEY=MY_SECRET_KEY\n   $ pip install tox\n   $ tox\n\nTox will attempt to run against all environments defined in the ``tox.ini``. It\nis recommended to use a tool like `pyenv <https://github.com/yyuu/pyenv>`_ to\nensure you have multiple versions of Python available on your machine for Tox to\nuse.\n\n\nFields\n------\n\n* ``_model_fields`` represent dictionary fields.\n\n.. note::\n\n   * ``_model_fields = [('address', Address)]`` AND\n   * ``Address`` subclasses ``BaseModel``\n\n.. code-block:: python\n\n   {\n      \"address\": {\n         \"street\": \"19 Charlotte St\",\n         \"city\": \"Toronto\",\n         \"state\": {\n            \"id\": \"CA-ON\",\n            \"href\": \"https://rest.gadventures.com/states/CA-ON\",\n            \"name\": \"Ontario\"\n         },\n         \"country\": {\n            \"id\": \"CA\",\n            \"href\": \"https://rest.gadventures.com/countries/CA\",\n            \"name\": \"Canada\"\n         },\n         \"postal_zip\": \"M5V 2H5\"\n      }\n   }\n\n\n* ``_model_collection_fields`` represent a list of dictionary fields.\n\n.. note::\n\n   * ``_model_collection_fields = [('emails', AgencyEmail),]`` AND\n   * ``AgencyEmail`` subclasses ``BaseModel``\n\n.. code-block:: python\n\n   {\n      \"emails\": [\n         {\n            \"type\": \"ALLOCATIONS_RELEASE\",\n            \"address\": \"g@gadventures.com\"\n         },\n         {\n            \"type\": \"ALLOCATIONS_RELEASE\",\n            \"address\": \"g2@gadventures.com\"\n         }\n      ]\n   }\n\n* ``_resource_fields`` refer to another ``Resource``\n\n\n\n\nContributing\n============\n\n.. note:: Ensure a Python 2 environment\n\n0. Clone the project\n\n   .. code-block:: sh\n\n      $ git clone git@github.com:gadventures/gapipy\n\n\n1. Run ``pip install -r requirements-dev.txt`` to setup dev dependencies.\n\n\n2. Always make your changes in a branch and to submit a PR.\n\n   .. code-block:: sh\n\n      $ git checkout master\n      $ git pull\n      $ git checkout -b feature-branch-name\n      $ git push origin feature-branch-name\n\n\n3. Once the PR has been accepted/merged into the ``master`` branch, follow\n   these steps.\n\n   .. code-block:: sh\n\n      $ cd /path/to/gapipy\n      $ git checkout master\n      $ git pull origin master\n\n\n**Modify the following files:**\n\n* Update **gapipy/__init__.py**\n\n   * increment the ``__version__`` variable\n\n   .. note::\n\n      * style ``major.minor.patch``\n      * update ``patch`` when adding new fields, fixing bugs introduced by a\n        minor release.\n      * update ``minor`` if there is some breaking change such as adding a new\n        resource, removing fields, adding new behaviour.\n      * update ``major`` when we switch to ``Python 3`` only support.\n      * See `semver.org <https://semver.org>`_ for more information.\n\n* Update **HISTORY.rst**\n\n   * update this file with the new ``version`` & ``date``\n   * Add some brief notes describing the changes.\n\n\n4. Use ``make dist`` to check the generated long_description rST file is valid.\n\n   .. note::\n\n      * ignore ``warning: no previously-included files matching`` messages.\n      * as long as you get a ``Checking dist/gapipy-a.b.c.tar.gz: PASSED``\n        message, you are good!\n      * If not, fix the errors as dictated in the output, and repeat.\n\n   Example output when running ``make dist``:\n\n   .. code-block:: sh\n\n      $ make dist\n      warning: no previously-included files matching '*' found under directory 'tests'\n      warning: no previously-included files matching '__pycache__' found under directory '*'\n      warning: no previously-included files matching '.eggs' found under directory '*'\n      warning: no previously-included files matching '*.py[co]' found under directory '*'\n      total 123\n      -rw-r--r--  1 user  group  76276  5 Feb 02:53 gapipy-a.b.c.tar.gz\n      Checking dist/gapipy-a.b.c.tar.gz: PASSED\n\n\n5. Push the new *Release* commit\n\n   * Use **Release a.b.c (YYYY-MM-DD)** format for the commit title. Optionally\n     add a description that matches the changes made to **HISTORY.rst**.\n\n\n6. Create a release on github with the following description (This will be\n   tagged to the ``Release`` commit and not the PR/change commit)\n\n   .. code-block:: md\n\n      # Release a.b.c (YYYY-MM-DD)\n\n      PR: #123\n\n      A brief description describing the changes\n      * bullet points\n      * make for easy reading\n\n\n7. Release!\n\n      $ make release\n\nThanks for helping!\n-------------------\n\n\n\nHistory\n=======\n\n2.36.0 (2024-05-30)\n-------------------\n\n* Add ``contact_us`` field to the ``AgenchChain`` resource. This field can be\n  ``None``, however should a value be present, it will be an object with three\n  accessible attributes: ``email``, ``phone_number``, and ``website_url``. See\n  the `PR #141`_ for more details.\n\n.. _`PR #141`: https://github.com/gadventures/gapipy/pull/141\n\n\n2.35.0 (2022-04-18)\n-------------------\n\n* Add new ``Client`` configuration value that will raise an error when an empty\n  partial update (PATCH) payload is computed by gapipy. See `Issue #136`_ and\n  the corresponding `PR #137`_ for more details.\n\n* The new Client configuration kwarg is ``raise_on_empty_update``, whose\n  default value is ``False``, and can also be set by passing it as an\n  environment variable ``GAPI_CLIENT_RAISE_ON_EMPTY_UPDATE``. If this config\n  value is set, then a call to ``Resource.save`` with ``partial=True`` will\n  raise the new ``EmptyPartialUpdateError`` if an empty payload is computed.\n\n  .. code-block:: python\n\n    from gapipy import Client\n\n    gapi = Client(application_key=\"your_api_key\", raise_on_empty_update=True)\n    departure_service = gapi.departure_services.get(123456)\n\n    # we've changed nothing and are calling a partial save (PATCH)\n    #\n    # NOTE: the new EmptyPartialUpdateError will be raised here\n    departure_service.save(partial=True)\n\n.. _`Issue #136`: https://github.com/gadventures/gapipy/issues/136\n.. _`PR #137`: https://github.com/gadventures/gapipy/pull/137\n\n\n2.34.0 (2021-08-20)\n-------------------\n\n* Add ``travel_ready_policy`` model field to the ``Departure`` resource.\n* More details can be found in our developer documentation.\n  c.f. `Departure travel-ready-policy`_\n\n.. _`Departure travel-ready-policy`: https://developers.gadventures.com/docs/departure.html#travel-ready-policy\n\n\n2.33.0 (2021-07-06)\n-------------------\n\n* Add ``online_preferences`` field to the ``Agency Chain`` resource.\n\n\n2.32.0 (2021-06-18)\n-------------------\n\n* Make ``future`` requirement more flexible. See `PR #134`_ for more details.\n\n.. _`PR #134`: https://github.com/gadventures/gapipy/pull/134\n\n\n2.31.1 (2021-05-14)\n-------------------\n\n* Initialize the ``DjangoCache`` via the ``BaseCache`` which exposes the\n  ``default_timeout`` attribute to the class. Prior to this change, when using\n  the ``DjangoCache``, items would persist forever as no timeout would be set\n  on the entries. See `PR #133`_ for more details.\n\n.. note:: ``DjangoCache`` was introduced in `2.30.0 (2021-02-08)`_\n\n.. _`PR #133`: https://github.com/gadventures/gapipy/pull/133\n\n\n2.31.0 (2021-03-02)\n-------------------\n\n* Introduce ``gapipy.constants`` module that holds common constants. See\n  `PR #132`_ for more details.\n\n* Reintroduce the ability to enable old behaviour (pre `2.25.0 (2020-01-02)`_)\n  for ``Resource.fetch``. It adds an optional ``httperrors_mapped_to_none``\n  parameter to the method (default ``None``), where if a list of HTTP Status\n  codes is provided instead, will silently consume errors mapped to those\n  status codes and return a ``None`` value instead of raising the HTTPError.\n  See `PR #131`_ for more details.\n\n.. _`PR #131`: https://github.com/gadventures/gapipy/pull/131\n.. _`PR #132`: https://github.com/gadventures/gapipy/pull/132\n\n\n2.30.1 (2021-02-08)\n-------------------\n\n* Fix for `2.30.0 (2021-02-08)`_ Adds a guard against configuring Django\n  settings again as per the `Django settings docs`_. See `PR #130`_ for more\n  details.\n\n.. _`Django settings docs`: https://docs.djangoproject.com/en/3.1/topics/settings/#either-configure-or-django-settings-module-is-required\n.. _`PR #130`: https://github.com/gadventures/gapipy/pull/130\n\n\n2.30.0 (2021-02-08)\n-------------------\n\n* Adds a new cache backend; ``gapipy.cache.DjangoCache``. It requires ``Django``\n  and a ``gapi`` entry in ``settings.CACHES``. See `PR #129`_ for more details.\n\n.. _`PR #129`: https://github.com/gadventures/gapipy/pull/129/\n\n**Usage:**\n\n* Set the ``GAPI_CACHE_BACKEND`` Env varible to ``gapipy.cache.DjangoCache``.\n\nOR\n\n.. code-block:: python\n\n   from gapipy import Client\n\n   gapi = Client(\n      application_key=\"live_your-secret-gapi-key\",\n      cache_backend=\"gapipy.cache.DjangoCache\",\n   )\n\n\n2.29.0 (2021-02-05)\n-------------------\n\n* Adds ``Departure.relationships`` field via ``DepartureRelationship`` model\n* Adds ``TourDossier.relationships`` field via ``TourDossierRelationship``\n  model\n\n.. warning:: BREAKING!\n\n* Moves the ``gapipy.resources.tour.itinerary.ValidDuringRange`` class over to\n  its own file ``gapipy.models.valid_duraing_range.ValidDuringRange``\n  so that it can be reused by the ``TourDossierRelationship`` model. Any code\n  importing the class directly will need to change the import path:\n\n   .. code-block:: python\n\n      # before\n      from gapipy.resources.tour.itinerary.ValidDuringRange\n\n      # now\n      from gapipy.models import ValidDuringRange\n\n* See `PR #128`_ for more details.\n\n.. _`PR #128`: https://github.com/gadventures/gapipy/pull/128/\n\n\n2.28.0 (2020-11-23)\n-------------------\n\n* Add a new ``Client`` config option, ``global_http_headers``, a dict of HTTP\n  headers to add to each request made with that client.\n\n  This is similar to the ``headers=`` kwargs available when making ``get`` and\n  ``create`` calls, except that the ``global_http_headers`` set on a client\n  will apply on *every request* made by that client instance.\n\n\n2.27.0 (2020-05-26)\n-------------------\n\n.. warning:: BREAKING!\n\n* Make ``Customer.nationality`` a *resource field*. This allows attribute style\n  access to the field values, whereas before they needed to be accessed using\n  dictionary accessor (``d[\"key\"]``) syntax.\n\n.. code-block:: python\n\n   # before\n   >>> api.customers.get(123456).nationality[\"name\"]\n   u'Canadian'\n\n   # now\n   >>> api.customers.get(123456).nationality.name\n   u'Canadian'\n\n\n2.26.4 (2020-04-28)\n-------------------\n\n* Fix `2.26.3 (2020-04-28) (Yanked)`_: Add missing ``CONTRIBUTING.rst`` to the\n  manifest.\n\n.. note:: Discovered when attempting to install ``gapipy`` via ``pip``.\n\n\n2.26.3 (2020-04-28) (Yanked)\n----------------------------\n\n* Fix py2 & py3 compatibility for ``urlparse``\n\n\n2.26.2 (2020-04-20)\n-------------------\n\n* Fix for `2.26.1 (2020-04-20)`_ and `Issue #113`_.\n\n   * See `PR #125`_.\n   * Remove the ``_set_resource_collection_field`` method in ``TourDossier``\n   * Introducing the ``_Parent`` namedtuple in `PR #123`_.\n     broke being able to Query-chain from Tour-Dossiers to departures\n   * Buggy behaviour fixed from `2.26.1 (2020-04-20)`_\n\n   .. code-block:: python\n\n      >>> from gapipy import Client\n      >>> api = Client(application_key='MY_SECRET_KEY')\n\n      >>> api.tour_dossiers(24309).departures.count()\n      # AttributeError: 'tuple' object has no attribute 'uri'\n\n.. _`PR #125`: https://github.com/gadventures/gapipy/pull/125\n\n\n2.26.1 (2020-04-20)\n-------------------\n\n* Fix for `2.26.0 (2020-04-14)`_ and `Issue #113`_.\n\n   * Calls to ``APIRequestor.list_raw`` will use initialised its parameters,\n     unless the URI provides its own.\n   * See `PR #123`_.\n\n* Add the ability to define the ``max_retries`` values on the requestor.\n\n   * New ``env`` value ``GAPI_CLIENT_MAX_RETRIES``.\n   * The default value will be ``0``, and if provided will override the ``retry``\n     value on the ``requests.Session``.\n   * This change will also always initialize a ``requests.Session`` value on\n     initialisation of the ``gapipy.Client``.\n   * See `PR #124`_.\n\n* Add ``variation_id`` field to the ``Image`` resource.\n\n   * See `Commit edc8d9b`_.\n\n* Update the ``ActivityDossier`` and ``AccommodationDossier`` resources.\n\n   * Remove the ``is_prepaid`` field.\n   * Adds the ``has_costs`` field.\n   * See `Commit bd35531`_. \n\n.. _`Issue #113`: https://github.com/gadventures/gapipy/issues/113\n.. _`PR #123`: https://github.com/gadventures/gapipy/pull/123\n.. _`PR #124`: https://github.com/gadventures/gapipy/pull/124\n.. _`Commit edc8d9b`: https://github.com/gadventures/gapipy/commit/edc8d9b\n.. _`Commit bd35531`: https://github.com/gadventures/gapipy/commit/bd35531\n\n\n2.26.0 (2020-04-14)\n-------------------\n\n.. warning:: BREAKING!\n\n* The ``Query.filter`` method will return a clone/copy of itself. This will\n  preserve the state of ``filters`` on the original Query object.\n* The ``Query.all`` method will **not** clear the filters after returning.\n* The ``Query.all`` method will return a ``TypeError`` if a type other than\n  an ``int`` is passed to the ``limit`` argument.\n* The ``Query.count`` method will **not** clear the filters after returning.\n* See `PR #121`_ for more details.\n\nNew behaviour with the ``Query.filter`` method:\n\n.. code-block:: python\n\n   >>> from gapipy import Client\n   >>> api = Client(application_key='MY_SECRET_KEY')\n\n   # create a filter on the departures\n   >>> query = api.departures.filter(**{\"tour_dossier.id\": \"24309\"})\n   >>> query.count()\n   494\n\n   # we preserve the filter status of the current query\n   >>> query.filter(**{\"availability.status\": \"AVAILABLE\"}).count()\n   80\n\n   >>> query.count()\n   494\n\n* The ``AgencyChain.agencies`` attribute returns a list of ``Agency`` objects.\n  See `Commit f34afd52`_.\n\n.. _`PR #121`: https://github.com/gadventures/gapipy/pull/121\n.. _`Commit f34afd52`: https://github.com/gadventures/gapipy/commit/f34afd52\n\n\n2.25.1 (2020-01-02)\n-------------------\n\n* Improve contribution instructions to check long_description rST file in dist\n* Dev Requirement updates:\n\n   * Add ``readme_renderer==24.0``\n   * Add ``twine==1.15.0`` for ``twine check`` command\n\n\n2.25.0 (2020-01-02)\n-------------------\n\n* Failing to fetch inlined Resource (from Stubs) will raise the underlying\n  requests.HTTPError instead of AttributeError resulting from a ``None``.\n* Adds ``httperrors_mapped_to_none`` kwarg to ``gapipy.query.Query.get``\n  with default value ``gapipy.query.HTTPERRORS_MAPPED_TO_NONE``\n* Modifies ``gapipy.resources.base.Resource.fetch`` to\n  pass ``httperrors_mapped_to_none=None`` to ``Query.get``\n* This ensures that any underlying ``requests.HTTPError`` from ``Query.get``\n  is bubbled up to the caller. It is most prevalent when reference Resource stubs\n  fail to be retrieved from the G API. Prior to this change ``Resource.fetch``\n  would return a ``None`` value resulting in an ``AttributeError``. Now, if the\n  stub fails to fetch due to an HTTPError, that will be raised instead\n\n\n2.24.3 (2019-12-12)\n-------------------\n\n* Exclude the ``tests`` package from the package distribution\n\n\n2.24.2 (2019-12-12)\n-------------------\n\n* Adds the ``compute_request_signature`` and ``compute_webhook_validation_key``\n  utility methods. See `PR #122`_.\n\n.. _`PR #122`: https://github.com/gadventures/gapipy/pull/122\n\n\n2.24.1 (2019-12-12)\n-------------------\n\n* Add ``slug`` field to ``TourDossier`` resource. See `PR #120`_.\n\n.. _`PR #120`: https://github.com/gadventures/gapipy/pull/120\n\n\n2.24.0 (2019-11-05)\n-------------------\n\n* Add missing/new fields to the following resources. See `PR #117`_.\n\n   * AccommodationDossier: ``categories``, ``suggested_dossiers``, ``visited_countries``, ``visited_cities``\n   * ActivityDossier: ``suggested_dossiers``, ``visited_countries``, ``visited_cities``\n   * Departure: ``local_payments``\n   * Itinerary: ``publish_state``\n\n* Add ``continent`` and ``place`` references to the ``Countries`` resource. See\n  `PR #115`_.\n* Accept ``additional_headers`` optional kwarg on ``create``. See `PR #114`_.\n\n.. _`PR #114`: https://github.com/gadventures/gapipy/pull/114\n.. _`PR #115`: https://github.com/gadventures/gapipy/pull/115\n.. _`PR #117`: https://github.com/gadventures/gapipy/pull/117\n\n\n2.23.0 (2019-11-04)\n-------------------\n\n* Remove deprecated ``tour_dossiers.itineraries`` field and related code\n\n\n2.22.0 (2019-10-10)\n-------------------\n\n* Add ``booking_company`` field to ``Booking`` resource\n\n\n2.21.0 (2019-04-09)\n-------------------\n\n* Add ``ripple_score`` to ``Itinerary`` resource\n\n\n2.20.1 (2019-02-20)\n-------------------\n\n* HISTORY.rst doc fixes\n\n\n2.20.0 (2019-02-20)\n-------------------\n\n* Add ``Requirement`` and ``RequirementSet`` resources\n* Move ``Checkin`` resource to the ``resources.booking`` module\n* The ``Query`` object will resolve to use the ``href`` value when\n  returning the iterator to fetch ``all`` of some resource. This is\n  needed because ``bookings/123456/requirements`` actually returns a list\n  of ``RequirementSet`` resources\n* See `Release tag 2.20.0`_ for more details.\n\n.. _`Release tag 2.20.0`: https://github.com/gadventures/gapipy/releases/tag/2.20.0\n\n\n2.19.4 (2019-02-14)\n-------------------\n\n* Add ``get_category_name`` helper method to ``TourDossier`` resource\n\n\n2.19.3 (2019-02-12)\n-------------------\n\n* Attempt to fix rST formatting of ``README`` and ``HISTORY`` on pypi\n\n\n2.19.2 (2019-02-12)\n-------------------\n\n* Become agnostic between redis ``2.x.x`` && ``3.x.x`` versions\n\n   * the ``setex`` method argument order changes between the major versions\n\n\n2.19.1 (2019-02-12)\n-------------------\n\n.. note:: HotFix for `2.19.0 (2019-02-12)`_.\n\n* adds ``requirements.txt`` file to the distribution ``MANIFEST``\n\n\n2.19.0 (2019-02-12)\n-------------------\n\n* Add ``booking_companies`` field to ``Itinerary`` resource\n* Pin our requirement/dependency versions\n\n   * pin ``future == 0.16.0``\n   * pin ``requests >= 2.18.4, < 3.0.0``\n   * read ``setup.py`` requirements from ``requirements.txt``\n\n\n2.18.1 (2019-02-07)\n-------------------\n\n* Add ``customers`` nested resource to ``bookings``\n\n\n2.18.0 (2018-12-14)\n-------------------\n\n* Add ``merchandise`` resource\n* Add ``merchandise_services`` resources\n\n\n2.17.0 (2018-11-12)\n-------------------\n\n* Add ``membership_programs`` field to the ``Customer`` resource\n\n\n2.16.0 (2018-11-07)\n-------------------\n\n* Completely remove the deprecated ``add_ons`` field from the Departure resource\n* Add missing fields to various Dossier resources\n\n   * AccommodationDossier: ``flags``, ``is_prepaid``, ``service_time``, ``show_on_reservation_sheet``\n   * ActivityDossier: ``is_prepaid``, ``service_time``, ``show_on_reservation_sheet``\n   * CountryDossier: ``flags``\n   * PlaceDossier: ``flags``\n   * TransportDossier: ``flags``\n\n* Add ``valid_during_ranges`` list field to the Itinerary resource. This field is\n  a list field of the newly added ``ValidDuringRange`` model (described below)\n* Add ``ValidDuringRange`` model. It consists of two date fields, ``start_date``,\n  and ``end_date``. It also provides a number of convenience methods to determine\n  if the date range provided is valid, or relative to some date.\n\n   * ``is_expired``: Is it expired relative to ``datetime.date.today``\n   * ``is_valid_today``: Is it valid relative to ``datetime.date.today``\n   * ``is_valid_during_range``: Is it valid for some give start/end date range\n   * ``is_valid_on_or_after_date``: Is it valid on or after some date\n   * ``is_valid_on_or_before_date``: Is it valid on or before some date\n   * ``is_valid_on_date``: Is it valid on some date\n   * ``is_valid_sometime``: Is it valid at all\n\n\n2.15.0 (2018-10-10)\n-------------------\n\n* Add ``country`` reference to ``Nationality`` resource.\n* Moved ``resources/bookings/nationality.py`` to ``resources/geo/*``.\n\n\n2.14.6 (2018-08-01)\n-------------------\n\n* Check for presence of ``id`` field directly in the Resource ``__dict__`` in\n  order to prevent a chicken/egg situation when attempting to ``save``. This is\n  needed due to the change introduced in 2.14.4, where we explicitly raise an\n  AttributeError when trying to access the ``id`` attribute.\n* Added ``service_code`` field for Activty & Accommodation Dossier resources.\n\n\n2.14.5 (2018-08-01)\n-------------------\n\n* deleted\n\n\n2.14.4 (2018-07-13)\n-------------------\n\n* Raise an ``AttributeError`` when trying to access ``id`` on\n  ``Resource.__getattr__``.\n* Don't send duplicate params when paginating through list results.\n* Implement ``first()`` method for ``Query``.\n\n2.14.3 (2018-05-29)\n-------------------\n\n* Expose Linked Bookings via the API.\n\n2.14.1 (2018-05-15)\n-------------------\n\n* Add ``booking_companies`` field to Agency resource.\n* Remove ``bookings`` field from Agency resource.\n* Add ``requirements`` as_is field to Departure Service resource.\n* Add ``policy_emergency_phone_number`` field to Insurance Service resource.\n\n\n2.14.0 (2018-05-15)\n-------------------\n\n* Remove deprecated ``add_ons`` field from ``Departure`` resource.\n* Add ``costs`` field to ``Accommodation`` & ``ActivityDossier`` resources.\n\n\n2.13.0 (2018-03-31)\n-------------------\n\n* Add ``meal_budgets`` list field to ``CountryDossier`` resource.\n* Add ``publish_state`` field to ``DossierFeatures`` resource.\n\n\n2.12.0 (2018-02-14)\n-------------------\n\n* Add optional ``headers`` parameter to Query.get to allow HTTP-Headers to be\n  passed. e.g. ``client.<resource>.get(1234, headers={'A':'a'})``. See\n  `PR #91`_.\n* Add ``preferred_display_name`` field to ``Agency`` resource. See `PR #92`_.\n* Add ``booking_companies`` array field to all Product-type resources. See\n  `PR #93`_.\n\n   * Accommodation\n   * Activity\n   * AgencyChain\n   * Departure\n   * SingleSupplement\n   * TourDossier\n   * Transport\n\n.. _`PR #91`: https://github.com/gadventures/gapipy/pull/91\n.. _`PR #92`: https://github.com/gadventures/gapipy/pull/92\n.. _`PR #93`: https://github.com/gadventures/gapipy/pull/93\n\n\n2.11.4 (2018-01-29)\n-------------------\n\n* Add ``agency_chain`` field to ``Booking`` resource\n* Add ``id`` field as part of the ``DossierDetail`` model See `PR #89`_.\n* Add ``agency_chains`` field to the ``Agency`` resource. See `PR #90`_.\n* See `Release tag 2.11.3`_ for more details.\n\n.. _`PR #89`: https://github.com/gadventures/gapipy/pull/89\n.. _`PR #90`: https://github.com/gadventures/gapipy/pull/90\n.. _`Release tag 2.11.3`: https://github.com/gadventures/gapipy/releases/tag/2.11.3\n\n\n2.11.0 (2017-12-18)\n-------------------\n\n* The ``Customer.address`` field uses the ``Address`` model, and is no longer a\n  dict.\n* Passing in ``uuid=True`` to ``Client`` kwargs enables ``uuid`` generation\n  for every request.\n\n\n2.10.0 (2017-12-01)\n-------------------\n\n* Add the ``amount_pending`` field to the ``Booking`` resource\n* The ``PricePromotion`` model extends from the ``Promotion`` resource (PR/85)\n* Update the ``Agent`` class to use BaseModel classes for the ``role``\n  and ``phone_numbers`` fields.\n* see `Release tag 2.10.0`_ for more details.\n\n.. _`Release tag 2.10.0`: https://github.com/gadventures/gapipy/releases/tag/2.10.0\n\n\n2.9.3 (2017-11-23)\n------------------\n\n.. note:: We have skipped Release ``2.9.2`` due to pypi upload issues.\n\n* Expose ``requirement_set`` for ``departure_services`` & ``activity_services``.\n\n\n2.9.1 (2017-11-22)\n------------------\n\n.. note:: * We have skipped Release ``2.9.0`` due to pypi upload issues.\n\n* Adds the ``options`` method on the Resource Query object. See\n  `Release tag 2.9.1`_ for more details.\n\n.. _`Release tag 2.9.1`: https://github.com/gadventures/gapipy/releases/tag/2.9.1\n\n\n2.8.2 (2017-11-14)\n------------------\n\n* Adds fields ``sale_start_datetime`` and ``sale_finish_datetime`` to the\n  Promotion resource. The fields mark the start/finish date-time values\n  for when a Promotion is applicable. The values represented are in UTC.\n\n\n2.8.1 (2017-10-25)\n------------------\n\n* Add new fields to the ``Agency`` and ``AgencyChain`` resources\n\n\n2.8.0 (2017-10-23)\n------------------\n\n* This release adds a behaviour change to the ``.all()`` method on resource\n  Query objects. Prior to this release, the base Resource Query object would\n  retain any previously added ``filter`` values, and be used in subsequent\n  calls. Now the underlying filters are reset after a ``<resource>.all()`` call\n  is made.\n\n  See `Issue #76`_ and `PR #77`_ for details and the resulting fix. \n\n* Adds missing fields to the Agency and Flight Service resources (PR/78)\n\n.. _`Issue #76`: https://github.com/gadventures/gapipy/issues/76\n.. _`PR #77`: https://github.com/gadventures/gapipy/pull/77\n\n\n2.7.6 (2017-10-04)\n------------------\n\n* Add ``agency`` field to ``Booking`` resource.\n\n\n2.7.5 (2017-09-25)\n------------------\n\n* Add test fix for Accommodation. It is a listable resource as of ``2.7.4``\n* Add regression test for departures.addon.product model\n  * Ensure Addon's are instantiated to the correct underlying model.\n  * Prior to this release, all Addon.product resources were instantiated as\n  ``Accommodation``.\n\n\n2.7.4 (2017-09-20)\n------------------\n\n* Add ``videos``, ``images``, and ``categories`` to ``Activity``, ``Transport``,\n  ``Place``, and ``Accommodation Dossier`` resources.\n* Add ``flags`` to Itinerary resource\n* Add list view of ``Accommodations`` resource\n\n\n2.7.3 (2017-09-06)\n------------------\n\n* Add ``type`` field to ``AgencyDocument`` model\n* Add ``structured_itinerary`` model collection field to ``Departure`` resource\n\n\n2.7.2 (2017-08-18)\n------------------\n\n* Fix flight_status Reference value in FlightService resource\n\n\n2.7.1 (2017-08-18)\n------------------\n\n* Fix: remove FlightStatus import reference for FlightService resource\n* Add fields (fixes two broken Resource tests)\n\n  * Add ``href`` field for ``checkins`` resource\n  * Add ``date_cancelled`` field for ``departures`` resource\n\n* Fix broken ``UpdateCreateResource`` tests\n\n\n2.7.0 (2017-08-18)\n------------------\n\n* Remove ``flight_statuses`` and ``flight_segments`` resources.\n\n\n2.6.2 (2017-08-11)\n------------------\n\n* Version bump\n\n\n2.6.1 (2017-08-11)\n------------------\n\n* Adds a Deprecation warning when using the ``tours`` resource.\n\n\n2.6.0 (2017-08-11)\n------------------\n\n* Fixed `Issue #65`_: only\n  write data into the local cache after a fetch from the API, do not write data\n  into the local cache when fetching from the local cache.\n\n.. _`Issue #65`: https://github.com/gadventures/gapipy/issues/65\n\n\n2.5.2 (2017-04-26)\n------------------\n\n* Added ``future`` dependency to setup.py\n\n\n2.5.1 (2017-02-08)\n------------------\n\n* Fixed an issue in which modifying a nested dictionary caused gapipy to not\n  identify a change in the data.\n* Added ``tox.ini`` for testing across Python platforms.\n* Capture ``403`` Status Codes as a ``None`` object.\n\n2.5.0 (2017-01-20)\n------------------\n\n* Provided Python 3 functionality (still Python 2 compatible)\n* Removed Python 2 only tests\n* Installed ``future`` module for smooth Python 2 to Python 3 migration\n* Remove ``DictToModel`` class and the associated tests\n* Add ``Dossier`` Resource(s)\n* Minor field updates to: ``Customer``, ``InsuranceService``,\n  ``DepartureService``, ``Booking``, ``FlightStatus``, ``State``\n\n\n2.4.9 (2016-11-22)\n------------------\n\n* Fixed a bug with internal ``_get_uri`` function.\n\n\n2.4.8 (2016-11-11)\n------------------\n\n* Adjusted ``Checkin`` resource to meet updated spec.\n\n\n2.4.7 (2016-10-25)\n------------------\n\n* Added ``Checkin`` resource.\n\n\n2.4.6 (2016-10-19)\n------------------\n\n* Fix broken ``Duration`` init in ``ActivityDossier`` (likely broke due to\n  changes that happened in 2.0.0)\n\n\n2.4.5 (2016-10-13)\n------------------\n\n* Added ``Image`` resource definition and put it to use in ``Itinerary`` and,\n  ``PlaceDossier``\n\n\n2.4.4 (2016-09-09)\n------------------\n\n* Added ``date_last_modified`` and ``date_created`` to ``Promotion``.\n\n\n2.4.3 (2016-09-06)\n------------------\n\n* Added ``gender`` to ``Customer``.\n* Added ``places_of_interest`` to ``Place``.\n\n\n2.4.2 (2016-07-08)\n------------------\n\n* Added ``departure`` reference to ``DepartureComponent``\n\n\n2.4.1 (2016-07-06)\n------------------\n\n* Removed use of ``.iteritems`` wherever present in favour of ``.items``\n* Added ``features`` representation to ``ActivityDossier`` and,\n  ``TransportDossier``\n\n\n2.4.0 (2016-06-29)\n------------------\n\n* Added ``CountryDossier`` resource.\n\n\n2.3.0 (2016-06-28)\n------------------\n\n* Added ``DossierSegment`` resource.\n* Added ``ServiceLevel`` resource.\n\n\n2.2.2 (2016-06-08)\n------------------\n\n* Added day ``label`` field to the ``Itinerary`` resource.\n\n\n2.2.1 (2016-06-06)\n------------------\n\n* Added ``audience`` field to the ``Document`` resource.\n\n\n2.2.0 (2016-05-17)\n------------------\n\n* Added ``transactional_email``, and ``emails`` to ``Agency`` resource.\n\n\n2.1.2 (2016-05-17)\n------------------\n\n* Added ``audience`` to ``Invoice`` resource.\n\n\n2.1.1 (2016-04-29)\n------------------\n\n* Removed invalid field, ``email`` from ``AgencyChain``\n\n\n2.1.0 (2016-04-25)\n------------------\n\n* Added new resource, ``AgencyChain``\n\n\n2.0.0 (2016-03-11)\n------------------\n\nThe global reference to the last instantiated ``Client`` has been removed. It\nis now mandatory to pass in a Client instance when instantiating a ``Model`` or\n``Resource``.\n\nIn practice, this should not introduce too many changes in codebases that are\nusing ``gapipy``, since most resource interacation happens through a ``Client``\ninstance (e.g. ``api.tours.get(123)``, or ``api.customers.create({...})``),\ninstead of being instantiated independently. The one possible exception is unit\ntesting: in that case, ``Client.build`` can be useful.\n\nThe global variable was causing issues with connection pooling when multiple\nclient with different configurations were used at the same time.\n\n\n1.1.0 (2016-03-11)\n------------------\n\n* Added new resource, ``DossierFeature``\n\n\n1.0.0 (2016-02-29)\n------------------\n\n* Adopted `Semantic Versioning`_ for this project.\n\n.. warning:: BREAKING!\n\n* Refactored how the cache key is set. This is a breaking change for any\n  modules that implemented their own cache interface. The cache modules are\n  no longer responsible for defining the cache value, but simply storing\n  whatever it is given into cache. The ``Query`` object now introduces a\n  ``query_key`` method which generates the cache key sent to the cache\n  modules.\n\n.. _`Semantic Versioning`: http://semver.org/\n\n\n0.6.3 (2016-01-21)\n------------------\n\n* Added better error handling to ``Client.build``. An AttributeError raised when\n  instantiating a resource won't be shadowed by the except block anymore.\n\n\n0.6.2 (2016-01-20)\n------------------\n\n* Fixed a regression bug when initializing DepartureServiceRoom model.\n\n\n0.6.1 (2016-01-20)\n------------------\n\n* Fixed a regression bug when initializing services.\n\n\n0.6.0 (2016-01-20)\n------------------\n\n* Fixed a bug when initializing list of resources.\n\n\n0.5.5 (2016-01-08)\n------------------\n\n* Added a component of type ``ACCOMMODATION`` to ``Itineraries``.\n\n\n0.5.4 (2016-01-04)\n------------------\n\n* Added ``associated_services`` to ``SingleSupplementService``\n\n\n0.5.3 (2015-12-31)\n------------------\n\n* Added ``name`` to ``Departure``.\n* Happy New Year!\n\n\n0.5.2 (2015-12-15)\n------------------\n\n* Added ``variation_id`` to ``BaseCache`` to fix a ``TypeError`` when using\n  the ``NullCache``\n\n\n0.5.1 (2015-12-14)\n------------------\n\n* Add ``associated_agency`` to ``bookings`` resource\n\n\n0.5.0 (2015-12-10)\n------------------\n\n* Minor adjusted in Query internals to ensure the ``variation_id`` of an\n  Itinerary is handled properly.\n* Added ``ItineraryHighlights`` and ``ItineraryMedia`` resources. These are\n  sub resources of the ``Itinerary``\n\n\n0.4.6 (2015-12-09)\n------------------\n\n* Added connection pool caching to ``RedisCache``. Instances of ``gapipy`` with\n  the same cache settings (in the same Python process) will share a connection\n  pool.\n\n\n0.4.5 (2015-11-05)\n------------------\n\n* Added ``code`` field to the ``type`` of an ``Itinerary``'s listed\n  ``details``.\n\n\n0.4.4 (2015-11-04)\n------------------\n\n* Added the ``details`` field to the ``Itinerary`` resource -- a list of\n  textual details about an itinerary.\n\n\n0.4.3 (2015-11-03)\n-------------------\n\n* Added the ``tour_dossier`` field to the ``Itinerary`` resource.\n\n\n0.4.2 (2015-10-28)\n------------------\n\n* Fixed a bug that would cause ``amount`` when looking at ``Promotion`` objects\n  in the ``Departure`` to be removed from the data dict.\n\n\n0.4.1 (2015-10-16)\n------------------\n\n* Moved an import of ``requests`` down from the module level. Fixes issues in\n  CI environments.\n\n\n0.4.0 (2015-10-13)\n------------------\n\n* Added connection pooling options, see docs for details on\n  ``connection_pool_options``.\n\n\n0.3.0 (2015-09-24)\n------------------\n\n* Modified how the ``Promotion`` object is loaded within ``price_bands`` on a\n  ``Departure``. It now correctly captures the ``amount`` field.\n\n\n0.2.0 (2015-09-15)\n------------------\n\n* Modified objects within ``cache`` module to handle ``variation_id``, which is\n  exposed within the ``Itinerary`` object. Previously, the ``Itinerary`` would\n  not be correctly stored in cache with its variant reference.\n\n\n0.1.51 (2015-08-31)\n-------------------\n\n* Added the ``components`` field to the ``Departure`` resource.\n\n\n0.1.50 (2015-07-28)\n-------------------\n\n* Fixed an issue with the default ``gapipy.cache.NullCache`` when ``is_cached``\n  was used.\n\n\n0.1.49 (2015-07-23)\n-------------------\n\n* Added new fields to ``Itinerary`` revolving around variations.\n* Added ``declined_reason`` to all service resources.\n\n\n0.1.48 (2015-07-15)\n-------------------\n\n* Add DeclinedReason resource\n\n\n0.1.47 (2015-07-08)\n-------------------\n\n* Fixed a bug in ``APIRequestor.get``. Requesting a resource with with an id of\n  ``0`` won't raise an Exception anymore.\n\n\n0.1.46 (2015-06-10)\n-------------------\n\n* Added ``associated_services`` and ``original_departure_service`` to various\n  service resources and ``departure_services`` model respectively.\n\n\n0.1.45 (2015-05-27)\n-------------------\n\n* Fixed ``products`` within the ``Promotion`` resource to properly retain\n  ``type`` and ``sub_type`` fields after being parsed into a dictionary.\n\n\n0.1.44 (2015-05-22)\n-------------------\n\n* Changed default ``cache_backend`` to use ``gapipy.cache.NullCache``.\n  Previously, ``SimpleCache`` was the default and led to confusion in\n  production environments, specifically as to why resources were not matching\n  the API output. Now, by default, to get any caching from gapipy you must\n  explicitly set it.\n\n\n0.1.43 (2015-04-29)\n-------------------\n\n* Fixed ``Place`` init with empty admin_divisions.\n\n\n0.1.42 (2015-04-29)\n-------------------\n\n* Added ``description`` to ``TourCategory`` resource.\n\n\n0.1.41 (2015-04-14)\n-------------------\n\n* Added ``DepartureComponent`` resource. See the official G API\n  `documentation <https://developers.gadventures.com/docs/departure_component.html>`_\n  for details.\n\n\n0.1.40 (2015-04-06)\n-------------------\n\n* Added ``deposit`` to ``DepartureService`` resource.\n\n\n0.1.39 (2015-03-31)\n-------------------\n\n* Refactor ``APIRequestor._request``. While this should not change existing\n  functionality, it is now possible to override specific methods on the class.\n\n\n0.1.38 (2015-03-23)\n-------------------\n\n* Fixed: Due to inconsistencies in the G API with regards to nested resources,\n  the ``fetch`` function was modified to use the raw data from the API, rather\n  than a specific set of allowed fields.\n\n\n0.1.37 (2015-03-23)\n-------------------\n\n* Fixed: Iterating over ``products`` within the ``promotions`` object now works\n  as expected. Previously, accessing the ``products`` attribute would result in\n  a Query object with incorrect parameters.\n\n\n0.1.36 (2015-03-17)\n-------------------\n\n* Support free to amount price range formatting (e.g. Free-10CAD)\n\n\n0.1.35 (2015-03-12)\n-------------------\n\n* Added ``duration_min`` & ``duration_max`` to ``ActivityDossier`` model\n\n\n0.1.34 (2015-03-11)\n-------------------\n\n* Added ``OptionalActivity`` model\n* All Dossiers with ``details``:\n  * Now represented as list of ``DossierDetail`` models\n  * Added convenience methods for retrieving specific details\n* ``ItineraryComponent`` and ``ActivityDossier`` use new ``Duration`` model\n  for their ``duration`` field/property\n* Added ``duration_label`` and ``location_label`` to ``ItineraryComponent``\n* Added ``duration_label``, ``price_per_person_label``, and\n  ``price_per_group_label`` to ``ActivityDossier``\n\n\n0.1.33 (2015-03-02)\n-------------------\n\n* Added ``name`` field to the Itinerary resource.\n\n\n0.1.32 (2015-02-18)\n-------------------\n\n* Changed cache key creation to account for ``GAPI_LANGUAGE`` when the\n  environment variable is set.\n\n\n0.1.31 (2015-02-18)\n-------------------\n\n* Fixed a bug when setting _resource_fields in ``DepartureService`` resource\n\n\n0.1.30 (2015-02-11)\n-------------------\n\n* ``TourDossier.structured_itineraries`` now refers to a list of Itinerary\n  resources\n\n\n0.1.29 (2015-02-10)\n-------------------\n\n* Added ``TransportDossier`` and ``Itinerary`` resources.\n\n* The reference to the itinerary in a ``DepartureService`` is now a\n  full-fledged ``Itinerary`` resource.\n\n\n0.1.28 (2015-01-22)\n-------------------\n\n* Bug fix to correctly send ``Content-Type: application/json`` in POST, PUT,\n  or PATCH.\n\n\n0.1.27 (2015-01-19)\n-------------------\n\n* Update ``DepartureService`` object to contain a reference to its\n  ``Itinerary``\n\n\n0.1.26 (2015-01-14)\n-------------------\n\n* Normalize API request headers, to promote caching.\n\n\n0.1.25 (2015-01-09)\n-------------------\n\n* Added ``ActivityDossier`` and ``AccommodationDossier`` resources, as well as\n  references to it from ``Activity`` and ``Accommodation``.\n\n\n0.1.24 (2015-01-07)\n-------------------\n\n* Added ``PlaceDossier`` resource, as well as reference to it from ``Place``\n\n\n0.1.22 (2014-12-12)\n-------------------\n\n* Added ``advertised_departures`` to ``TourDossier``\n\n\n0.1.21 (2014-11-26)\n-------------------\n\n* Fixed a bug with promotions on a Price object. When promotions were accessed,\n  gapipy would query for all promotions, rather than returning the inline list.\n\n\n0.1.20 (2014-11-20)\n-------------------\n\n* Departure resource is now listable via filters.\n\n\n0.1.19 (2014-11-17)\n-------------------\n\n* Fixed a bug with ``RedisCache`.is_cached` where it would not use the set\n  ``key_prefix`` when checking for existence in cache. Effectively, it would\n  always return False\n\n\n0.1.18 (2014-11-12)\n-------------------\n\n* When setting a ``date_field``, initiate it as a ``datetime.date`` type.\n\n\n0.1.17 (2014-11-07)\n-------------------\n\n* Deprecated ``RedisHashCache`` from cache backends available by default. Was not\n  well tested or reliable.\n\n\n0.1.16 (2014-10-28)\n---------------------\n\n* Fixed a bug where if a model field received ``null`` as a value, it would fail.\n  Now, if the result is ``null``, the model field will have an appropriate ``None``\n  value.\n\n\n0.1.15 (2014-10-23)\n-------------------\n\n* Fix a bug in the DepartureRoom model. The ``price_bands`` attribute is now\n  properly set.\n\n\n0.1.14 (2014-10-22)\n-------------------\n\n* Fixed a bug where AgencyDocument was not included in the code base.\n\n\n0.1.13 (2014-10-21)\n-------------------\n\n* Add ``latitude``, ``longitude``, and ``documents`` to the ``Agency``\n  resource.\n\n\n0.1.12 (2014-10-20)\n-------------------\n\n* ``date_created`` on the ``Agency`` resource is correctly parsed as a local\n  time.\n\n\n0.1.11 (2014-10-15)\n-------------------\n\n* Improve the performance of ``Resource.fetch`` by handling cache get/set.\n\n\n0.1.10 (2014-10-09)\n-------------------\n\n* Fix a bug in AccommodationRoom price bands. The ``season_dates`` and\n  ``blackout_dates`` attributes are now properly set.\n\n\n0.1.9 (2014-09-23)\n------------------\n\n* Add `iso_639_3` and `iso_639_1` to ``Language``\n\n\n0.1.8 (2014-09-17)\n------------------\n\n* Remove the ``add_ons`` field in ``Departure``, and add ``addons``.\n\n\n0.1.7 (2014-08-22)\n------------------\n\n* Fix a bug when initializing AccommodationRoom from cached data.\n\n\n0.1.6 (2014-08-19)\n------------------\n\n* Add Query.purge_cached\n\n\n0.1.5 (2014-07-29)\n------------------\n\n* Add ``details`` field to the list of ``incomplete_requirements`` in a\n  ``DepartureService``.\n\n\n0.1.4 (2014-07-21)\n------------------\n\n* Removed sending of header `X-HTTP-Method-Override: PATCH` when the update\n  command is called. Now, when `.save(partial=True)` is called, the\n  correct PATCH HTTP method will be sent with the request.\n\n\n0.1.3 (2014-07-18)\n------------------\n\n* Return ``None`` instead of raising a HTTPError 404 exception when fetching a\n  non-existing resource by id.\n* Added ability to create resources from the Query objects on the client\n  instance.\n\n.. code-block:: python\n\n   obj = {'name': {'legal_first_name': 'Pat', ...}, ...}\n   api.customers.create(obj)\n\n\n0.1.2 (2014-07-14)\n------------------\n\n* Added Query.is_cached\n* Added cache options\n\n\n0.1.1 (2014-06-27)\n------------------\n\n* Use setuptools find_packages\n\n\n0.1.0 (2014-06-20)\n------------------\n\n* First release on PyPI.",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Python client for the G Adventures REST API",
    "version": "2.36.0",
    "project_urls": {
        "Homepage": "https://github.com/gadventures/gapipy"
    },
    "split_keywords": [
        "gapipy"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f6a3c0094cfbe535e778c6383322da614da1cab53bd406ad176e7f7f67d07456",
                "md5": "ce78022b4ff95a9fb35d4c3693a102d2",
                "sha256": "26b37d26d195ee48f3f66b063ecf1f5b527b85832ab9f23aacbd7cd1774f200a"
            },
            "downloads": -1,
            "filename": "gapipy-2.36.0.tar.gz",
            "has_sig": false,
            "md5_digest": "ce78022b4ff95a9fb35d4c3693a102d2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 82872,
            "upload_time": "2024-05-30T19:10:08",
            "upload_time_iso_8601": "2024-05-30T19:10:08.856210Z",
            "url": "https://files.pythonhosted.org/packages/f6/a3/c0094cfbe535e778c6383322da614da1cab53bd406ad176e7f7f67d07456/gapipy-2.36.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-05-30 19:10:08",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "gadventures",
    "github_project": "gapipy",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "requirements": [],
    "tox": true,
    "lcname": "gapipy"
}
        
Elapsed time: 0.39056s