├── .codeclimate.yml ├── .coveragerc ├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.rst ├── cannabis_reports ├── __init__.py ├── apis │ ├── __init__.py │ ├── abstract_entity_endpoint.py │ ├── abstract_item_endpoint.py │ ├── abstract_product_endpoint.py │ ├── dispensaries.py │ ├── edibles.py │ ├── extracts.py │ ├── flowers.py │ ├── producers.py │ ├── products.py │ └── strains.py ├── auth_proxy.py ├── base_api.py ├── base_model.py ├── exceptions.py ├── models │ ├── __init__.py │ ├── abstract_item.py │ ├── address.py │ ├── dispensary.py │ ├── edible.py │ ├── effects_flavors.py │ ├── extract.py │ ├── flower.py │ ├── menu_item.py │ ├── producer.py │ ├── product.py │ ├── review.py │ ├── seed_company.py │ ├── strain.py │ └── user.py ├── request_paginator │ └── __init__.py └── tests │ ├── __init__.py │ ├── api_common.py │ ├── api_entity.py │ ├── api_product.py │ ├── fixtures │ └── cassettes │ │ ├── test_apis_dispensaries_get.yml │ │ ├── test_apis_dispensaries_get_available.yml │ │ ├── test_apis_dispensaries_get_edibles.yml │ │ ├── test_apis_dispensaries_get_extracts.yml │ │ ├── test_apis_dispensaries_get_products.yml │ │ ├── test_apis_dispensaries_get_strains.yml │ │ ├── test_apis_dispensaries_list.yml │ │ ├── test_apis_edibles_get.yml │ │ ├── test_apis_edibles_get_available.yml │ │ ├── test_apis_edibles_get_effects_flavors.yml │ │ ├── test_apis_edibles_get_producer.yml │ │ ├── test_apis_edibles_get_review.yml │ │ ├── test_apis_edibles_get_strain.yml │ │ ├── test_apis_edibles_get_user.yml │ │ ├── test_apis_edibles_list.yml │ │ ├── test_apis_edibles_search.yml │ │ ├── test_apis_extracts_get.yml │ │ ├── test_apis_extracts_get_available.yml │ │ ├── test_apis_extracts_get_effects_flavors.yml │ │ ├── test_apis_extracts_get_producer.yml │ │ ├── test_apis_extracts_get_review.yml │ │ ├── test_apis_extracts_get_strain.yml │ │ ├── test_apis_extracts_get_user.yml │ │ ├── test_apis_extracts_list.yml │ │ ├── test_apis_extracts_search.yml │ │ ├── test_apis_flowers_get.yml │ │ ├── test_apis_flowers_get_available.yml │ │ ├── test_apis_flowers_get_effects_flavors.yml │ │ ├── test_apis_flowers_get_producer.yml │ │ ├── test_apis_flowers_get_review.yml │ │ ├── test_apis_flowers_get_strain.yml │ │ ├── test_apis_flowers_get_user.yml │ │ ├── test_apis_flowers_list.yml │ │ ├── test_apis_flowers_search.yml │ │ ├── test_apis_producers_get.yml │ │ ├── test_apis_producers_get_available.yml │ │ ├── test_apis_producers_get_edibles.yml │ │ ├── test_apis_producers_get_extracts.yml │ │ ├── test_apis_producers_get_products.yml │ │ ├── test_apis_producers_list.yml │ │ ├── test_apis_products_get.yml │ │ ├── test_apis_products_get_available.yml │ │ ├── test_apis_products_get_effects_flavors.yml │ │ ├── test_apis_products_get_producer.yml │ │ ├── test_apis_products_get_review.yml │ │ ├── test_apis_products_get_strain.yml │ │ ├── test_apis_products_get_user.yml │ │ ├── test_apis_products_list.yml │ │ ├── test_apis_products_search.yml │ │ ├── test_apis_strains_get.yml │ │ ├── test_apis_strains_get_available.yml │ │ ├── test_apis_strains_get_children.yml │ │ ├── test_apis_strains_get_effects_flavors.yml │ │ ├── test_apis_strains_get_genetics.yml │ │ ├── test_apis_strains_get_review.yml │ │ ├── test_apis_strains_get_seed_company.yml │ │ ├── test_apis_strains_get_user.yml │ │ ├── test_apis_strains_list.yml │ │ └── test_apis_strains_search.yml │ ├── test_apis_dispensaries.py │ ├── test_apis_edibles.py │ ├── test_apis_extracts.py │ ├── test_apis_flowers.py │ ├── test_apis_producer.py │ ├── test_apis_products.py │ ├── test_apis_strains.py │ ├── test_base_api.py │ ├── test_base_model.py │ ├── test_cannabis_reports.py │ ├── test_exceptions.py │ └── test_request_paginator.py ├── setup.py └── test_requirements.txt /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | languages: 2 | JavaScript: false 3 | Python: true 4 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | 3 | branch = True 4 | 5 | [report] 6 | 7 | exclude_lines = 8 | pragma: no cover 9 | def __repr__ 10 | if self.debug: 11 | raise NotImplementedError 12 | if __name__ == .__main__.: 13 | 14 | ignore_errors = True 15 | 16 | include = 17 | */cannabis_reports/* 18 | 19 | omit = 20 | */virtualenv/* 21 | */tests/* 22 | setup.py 23 | */__init__.py 24 | tests.py 25 | 26 | [xml] 27 | 28 | output = coverage.xml 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | 91 | # Pycharm 92 | .idea/* 93 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | addons: 2 | apt: 3 | packages: 4 | - expect-dev 5 | language: python 6 | python: 7 | - '2.7' 8 | - '3.4' 9 | - '3.5' 10 | - '3.6' 11 | - '3.7-dev' 12 | env: 13 | global: 14 | - PROJECT="Cannabis Reports" 15 | - INTERSPHINX="requests=http://docs.python-requests.org/en/latest, properties=https://propertiespy.readthedocs.io/en/latest" 16 | matrix: 17 | - TESTS="1" 18 | - DOCS="1" 19 | - LINT="1" 20 | install: 21 | - git clone --depth=1 https://github.com/LasLabs/python-quality-tools.git ${HOME}/python-quality-tools 22 | - export PATH=${HOME}/python-quality-tools/travis:${PATH} 23 | - travis_install 24 | script: 25 | - travis_run 26 | after_success: 27 | - travis_after_success 28 | deploy: 29 | provider: pypi 30 | user: laslabs 31 | password: 32 | secure: u45JOJrCYLXhUEacnNVSC+wdhYV/+nFUN1UdcCjBfupoL4FXCaHvpdkLqZeKk8Q6QO0fRfI6gJXHAABGDPhKkGgOqgWbWKZivfkHtGBkvzVFlWkXSjc9sQe7o6/mkE2rc14eXkr5ViTi9DAlaSbnN6qAydmLTcRZrH+az75pBObU1UXiONHA3LAViEnXcaKNRnsPcGnaSxLCi0WMmVFuAMvKfR46VhfZbJk1DcpDyO4JyKw6pr0P69aUtms5NT0phbg852hELFOXTL8r/Ufw5wF36SrE9/W43B0PNW+WXS7gxDC5z2rG2HkEUF3J3SJYQ9foFZ7d90KTD3kG2/oGltBIFYhXgch/Jo3cLbpTCAcqgH9VtuOvM6M6vWiYTtTiUhJ3xoh5xG+NU7h7liKzBUFV+WvcEQ2uT4AfdZR0Bba2ExkOYcA2dgLv33ofZllXrpDGl9gspcRXbsqkxCcCWYfVRnOh7o5L0Heyi0fFg/i7N7CHDCKr0P1OVTUP4DnsqJC9Jb7K851i32xTiTBYs2uGrFvuExdN2WD1Ah2WDeoUER5tvHDe7oIEiHEHkmXh3QjBprVYY1pyztbQMOL6lXMR6BB7oBSKq7KmKPCBVNuajeK2yTfXnJv3WkQLazznCU5pLyRREaiJnB7sV1zS8sp89yzri3TE8zqIf6k2TDg= 33 | skip_cleanup: false 34 | skip_upload_docs: true 35 | on: 36 | repo: LasLabs/python-cannabis-reports 37 | branch: master 38 | tags: true 39 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright `2017` `LasLabs Inc.` 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated documentation 8 | files (the “Software”), to deal in the Software without 9 | restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | OTHER DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /cannabis_reports/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from requests import Session 6 | 7 | from .auth_proxy import AuthProxy 8 | from .base_api import BaseApi 9 | from .base_model import BaseModel 10 | 11 | from . import exceptions 12 | 13 | 14 | class CannabisReports(object): 15 | """This object is the primary point of interaction with CannabisReports. 16 | 17 | Properties will be set on this ``CannabisReports`` instance that will 18 | mirror the class names of APIs in the ``cannabis_reports.api`` module. 19 | 20 | These API classes are naive of authentication, so the actual properties 21 | set will be using the ``AuthProxy`` class, which will transparently 22 | inject authentication into the API requests while still allowing for a 23 | naive API object. 24 | 25 | This allows for the ``CannabisReports`` instance to act as a container for 26 | all of the authenticated API objects. 27 | 28 | Examples:: 29 | 30 | from cannabis_reports import CannabisReports 31 | cr = CannabisReports('api_key') 32 | for strain in cr.Strains.list(): 33 | print(strain.serialize()) 34 | """ 35 | 36 | __apis__ = {} 37 | 38 | def __init__(self, api_key=None): 39 | """Initialize a new CannabisReports client. 40 | 41 | Args: 42 | api_key (str, optional): The API key to use for this session. 43 | """ 44 | self.session = Session() 45 | if api_key: 46 | self.session.headers.update({ 47 | 'X-API-Key': api_key, 48 | }) 49 | self._load_apis() 50 | 51 | def _load_apis(self): 52 | """Find available APIs and set instances property auth proxies.""" 53 | cannabis_reports = __import__('cannabis_reports.apis') 54 | for class_name in cannabis_reports.apis.__all__: 55 | if not class_name.startswith('_'): 56 | cls = getattr(cannabis_reports.apis, class_name) 57 | api = AuthProxy(self.session, cls) 58 | setattr(self, class_name, api) 59 | self.__apis__[class_name] = api 60 | 61 | 62 | __all__ = [ 63 | 'AuthProxy', 64 | 'BaseApi', 65 | 'BaseModel', 66 | 'exceptions', 67 | 'CannabisReports', 68 | ] 69 | -------------------------------------------------------------------------------- /cannabis_reports/apis/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .dispensaries import Dispensaries 6 | from .edibles import Edibles 7 | from .extracts import Extracts 8 | from .flowers import Flowers 9 | from .producers import Producers 10 | from .products import Products 11 | from .strains import Strains 12 | 13 | __all__ = [ 14 | 'Dispensaries', 15 | 'Edibles', 16 | 'Extracts', 17 | 'Flowers', 18 | 'Producers', 19 | 'Products', 20 | 'Strains', 21 | ] 22 | -------------------------------------------------------------------------------- /cannabis_reports/apis/abstract_entity_endpoint.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .. import BaseApi 6 | 7 | from ..exceptions import CannabisReportsValidationException 8 | 9 | from ..models.edible import Edible 10 | from ..models.extract import Extract 11 | from ..models.menu_item import MenuItemSummary 12 | from ..models.product import Product 13 | 14 | 15 | class AbstractEntityEndpoint(BaseApi): 16 | """This represents an abstract entity endpoint. 17 | 18 | The Dispensaries and Producers API inherit from this. 19 | """ 20 | 21 | @classmethod 22 | def get_extracts(cls, session, ucpc, path_prefix=None, limit=None): 23 | """Gets a paginated list of extracts for a producer with the 24 | given UCPC. 25 | 26 | Args: 27 | session (requests.sessions.Session): Authenticated session. 28 | ucpc (str): `UCPC `_ for 30 | the cannabis producer you want the extracts for. 31 | path_prefix (str, optional): A URI path to prefix with, which 32 | is useful for dispensary hierarchies. This will override 33 | the endpoint prefix, so it should include it if necessary. 34 | limit (int, optional): Stop after iterating this many pages. 35 | 36 | Returns: 37 | RequestPaginator(output_type=Extract): 38 | The extracts for this producer. 39 | """ 40 | return cls( 41 | '/%s/%s/extracts' % (path_prefix or cls.__endpoint__, ucpc), 42 | session=session, 43 | out_type=Extract, 44 | iteration_limit=limit, 45 | ) 46 | 47 | @classmethod 48 | def get_edibles(cls, session, ucpc, path_prefix=None, limit=None): 49 | """Gets a paginated list of edibles for a producer with the given 50 | UCPC. 51 | 52 | Args: 53 | session (requests.sessions.Session): Authenticated session. 54 | ucpc (str): `UCPC `_ for 56 | the cannabis producer you want the edibles for. 57 | path_prefix (str, optional): A URI path to prefix with, which 58 | is useful for dispensary hierarchies. This will override 59 | the endpoint prefix, so it should include it if necessary. 60 | limit (int, optional): Stop after iterating this many pages. 61 | 62 | Returns: 63 | RequestPaginator(output_type=Edible): 64 | The edibles for this producer. 65 | """ 66 | return cls( 67 | '/%s/%s/edibles' % (path_prefix or cls.__endpoint__, ucpc), 68 | session=session, 69 | out_type=Edible, 70 | iteration_limit=None, 71 | ) 72 | 73 | @classmethod 74 | def get_products(cls, session, ucpc, path_prefix=None, limit=None): 75 | """Gets a paginated list of products for a producer with the given 76 | UCPC. 77 | 78 | Args: 79 | session (requests.sessions.Session): Authenticated session. 80 | ucpc (str): `UCPC `_ for 82 | the cannabis producer you want the products for. 83 | path_prefix (str, optional): A URI path to prefix with, which 84 | is useful for dispensary hierarchies. This will override 85 | the endpoint prefix, so it should include it if necessary. 86 | limit (int, optional): Stop after iterating this many pages. 87 | 88 | Returns: 89 | RequestPaginator(output_type=Product): 90 | The products for this producer. 91 | """ 92 | return cls( 93 | '/%s/%s/products' % (path_prefix or cls.__endpoint__, ucpc), 94 | session=session, 95 | out_type=Product, 96 | iteration_limit=None, 97 | ) 98 | 99 | @classmethod 100 | def get_available(cls, session, ucpc, lat, lng, radius=10, 101 | path_prefix=None, limit=None): 102 | """Get information about the availability of everything from a 103 | producer using latitude and longitude. 104 | 105 | Args: 106 | session (requests.sessions.Session): Authenticated session. 107 | ucpc (str): `UCPC `_ for 109 | the cannabis object you want the children from. 110 | lat (float): Latitude for the center of your availability search. 111 | lng (float): Longitude for the center of your availability search. 112 | radius (int): Radius to search for in miles, max 25. 113 | path_prefix (str, optional): A URI path to prefix with, which 114 | is useful for dispensary hierarchies. This will override 115 | the endpoint prefix, so it should include it if necessary. 116 | limit (int, optional): Stop after iterating this many pages. 117 | 118 | Returns: 119 | RequestPaginator(output_type=cls.__object__): 120 | An iterator of child objects. 121 | """ 122 | if radius > 25: 123 | raise CannabisReportsValidationException( 124 | 'The max search radius is 25.', 125 | ) 126 | return cls( 127 | '/%s/%s/availability/geo/%s/%s/%s' % ( 128 | path_prefix or cls.__endpoint__, ucpc, lat, lng, radius, 129 | ), 130 | session=session, 131 | out_type=MenuItemSummary, 132 | iteration_limit=limit, 133 | ) 134 | -------------------------------------------------------------------------------- /cannabis_reports/apis/abstract_item_endpoint.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .. import BaseApi, BaseModel 6 | 7 | from ..exceptions import CannabisReportsValidationException 8 | 9 | from ..models.effects_flavors import EffectsFlavors 10 | from ..models.menu_item import MenuItemSummary 11 | from ..models.review import Review 12 | from ..models.user import User 13 | 14 | 15 | class AbstractItemEndpoint(BaseApi): 16 | """This represents an abstract item endpoint. 17 | 18 | The Strains API and AbstractProductEndpoint inherit from this. 19 | """ 20 | 21 | @classmethod 22 | def get_user(cls, session, ucpc): 23 | """Get the user who added the object to the database. 24 | 25 | Args: 26 | session (requests.sessions.Session): Authenticated session. 27 | ucpc (str): `UCPC `_ for 29 | the cannabis object you want the user from. 30 | 31 | Returns: 32 | cannabis_reports.models.User: The user who added the object 33 | to the database. 34 | """ 35 | return cls( 36 | '/%s/%s/user' % (cls.__endpoint__, ucpc), 37 | session=session, 38 | singleton=True, 39 | out_type=User, 40 | ) 41 | 42 | @classmethod 43 | def get_reviews(cls, session, ucpc, limit=None): 44 | """Get the reviews for a cannabis object. 45 | 46 | Args: 47 | session (requests.sessions.Session): Authenticated session. 48 | ucpc (str): `UCPC `_ for 50 | the cannabis object you want the reviews from. 51 | limit (int, optional): Stop after iterating this many pages. 52 | 53 | Returns: 54 | RequestPaginator(output_type=cannabis_reports.models.Review): 55 | Reviews iterator. 56 | """ 57 | return cls( 58 | '/%s/%s/reviews' % (cls.__endpoint__, ucpc), 59 | session=session, 60 | out_type=Review, 61 | iteration_limit=limit, 62 | ) 63 | 64 | @classmethod 65 | def get_effects_flavors(cls, session, ucpc): 66 | """Get the average effects and flavors from reviews for this object. 67 | 68 | Args: 69 | session (requests.sessions.Session): Authenticated session. 70 | ucpc (str): `UCPC `_ for 72 | the cannabis object you want the effect and flavor profile 73 | from. 74 | 75 | Returns: 76 | cannabis_reports.models.EffectsFlavors: The effect and flavor 77 | profile for this object. 78 | """ 79 | return cls( 80 | '/%s/%s/effectsFlavors' % (cls.__endpoint__, ucpc), 81 | session=session, 82 | out_type=EffectsFlavors, 83 | singleton=True, 84 | ) 85 | 86 | @classmethod 87 | def get_available(cls, session, ucpc, lat, lng, radius=10, limit=None): 88 | """Get information about the availability of the given UCPC. 89 | 90 | Args: 91 | session (requests.sessions.Session): Authenticated session. 92 | ucpc (str): `UCPC `_ for 94 | the cannabis object you want the children from. 95 | lat (float): Latitude for the center of your availability search. 96 | lng (float): Longitude for the center of your availability search. 97 | radius (int): Radius to search for in miles, max 25. 98 | limit (int, optional): Stop after iterating this many pages. 99 | 100 | Returns: 101 | RequestPaginator(output_type=cls.__object__): 102 | An iterator of child objects. 103 | """ 104 | if radius > 25: 105 | raise CannabisReportsValidationException( 106 | 'The max search radius is 25.', 107 | ) 108 | return cls( 109 | '/%s/%s/availability/geo/%s/%s/%s' % ( 110 | cls.__endpoint__, ucpc, lat, lng, radius, 111 | ), 112 | session=session, 113 | out_type=MenuItemSummary, 114 | iteration_limit=limit, 115 | ) 116 | 117 | @classmethod 118 | def search(cls, session, query, sort='created_at', path='type', 119 | limit=None): 120 | """Return search results for objects. 121 | 122 | Args: 123 | session (requests.sessions.Session): Authenticated session. 124 | query (str): Search query to find objects in our system. 125 | Must be at least 2 characters. 126 | sort (str): Snake cased field name to sort on. Prefix with a `-` 127 | for descending. 128 | path (str): The path for the search (eg for ``strains`` it is 129 | ``search`` and for ``flowers`` it is ``type``. 130 | limit (int, optional): Stop after iterating this many pages. 131 | 132 | Returns: 133 | RequestPaginator(output_type=cls.__object__): 134 | Objects iterator. 135 | """ 136 | if not query or len(query) < 2: 137 | raise CannabisReportsValidationException( 138 | 'Search query must be at least 2 characters.', 139 | ) 140 | data = { 141 | sort: BaseModel._to_camel_case(sort) 142 | } 143 | return cls( 144 | '/%s/%s/%s' % (cls.__endpoint__, path, query), 145 | session=session, 146 | data=data, 147 | iteration_limit=limit, 148 | ) 149 | -------------------------------------------------------------------------------- /cannabis_reports/apis/abstract_product_endpoint.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .abstract_item_endpoint import AbstractItemEndpoint 6 | 7 | from ..models.producer import Producer 8 | from ..models.strain import Strain 9 | 10 | 11 | class AbstractProductEndpoint(AbstractItemEndpoint): 12 | """This represents an abstract product endpoint. 13 | 14 | The Edibles, Extracts, Flowers, Products APIs inherit from this. 15 | """ 16 | 17 | @classmethod 18 | def get_producer(cls, session, ucpc): 19 | """Gets the producer for a given product. 20 | 21 | Args: 22 | session (requests.sessions.Session): Authenticated session. 23 | ucpc (str): `UCPC `_ for 25 | the cannabis product you want the seed company from. 26 | 27 | Returns: 28 | cannabis_reports.models.SeedCompany: The producer that was 29 | responsible for this product. 30 | """ 31 | return cls( 32 | '/%s/%s/producer' % (cls.__endpoint__, ucpc), 33 | session=session, 34 | out_type=Producer, 35 | singleton=True, 36 | ) 37 | 38 | @classmethod 39 | def get_strain(cls, session, ucpc): 40 | """Gets the information about a strain for a product with the given 41 | UCPC. 42 | 43 | Args: 44 | session (requests.sessions.Session): Authenticated session. 45 | ucpc (str): `UCPC `_ for 47 | the cannabis product you want the strain from. 48 | 49 | Returns: 50 | cannabis_reports.models.Strain: The strain for the product. 51 | """ 52 | return cls( 53 | '/%s/%s/strain' % (cls.__endpoint__, ucpc), 54 | session=session, 55 | out_type=Strain, 56 | singleton=True, 57 | ) 58 | -------------------------------------------------------------------------------- /cannabis_reports/apis/dispensaries.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .abstract_entity_endpoint import AbstractEntityEndpoint 6 | 7 | from ..models.dispensary import Dispensary 8 | from ..models.strain import Strain 9 | 10 | 11 | class Dispensaries(AbstractEntityEndpoint): 12 | """This represents the ``Dispensaries`` Endpoint. 13 | 14 | https://developers.cannabisreports.com/docs/dispensaries 15 | """ 16 | 17 | __object__ = Dispensary 18 | __endpoint__ = 'dispensaries' 19 | 20 | @classmethod 21 | def get_strains(cls, session, slug, limit=None): 22 | """Gets a paginated list of strains for a dispensary with the 23 | given slug. 24 | 25 | Args: 26 | session (requests.sessions.Session): Authenticated session. 27 | slug (str): Slug for the name of the dispensary (includes 28 | city/state slug). 29 | limit (int, optional): Stop after iterating this many pages. 30 | 31 | Returns: 32 | RequestPaginator(output_type=Strain): 33 | The strains for this dispensary. 34 | """ 35 | return cls( 36 | '/%s/%s/strains' % (cls.__endpoint__, slug), 37 | session=session, 38 | out_type=Strain, 39 | iteration_limit=limit, 40 | ) 41 | 42 | @classmethod 43 | def get_available(cls, *args, **kwargs): 44 | raise NotImplementedError( 45 | 'This endpoint does not implement availability searches.', 46 | ) 47 | -------------------------------------------------------------------------------- /cannabis_reports/apis/edibles.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .abstract_product_endpoint import AbstractProductEndpoint 6 | 7 | from ..models.edible import Edible 8 | 9 | 10 | class Edibles(AbstractProductEndpoint): 11 | """This represents the ``Edibles`` Endpoint. 12 | 13 | https://developers.cannabisreports.com/docs/edibles 14 | """ 15 | 16 | __object__ = Edible 17 | __endpoint__ = 'edibles' 18 | -------------------------------------------------------------------------------- /cannabis_reports/apis/extracts.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .abstract_product_endpoint import AbstractProductEndpoint 6 | 7 | from ..models.extract import Extract 8 | 9 | 10 | class Extracts(AbstractProductEndpoint): 11 | """This represents the ``Extracts`` Endpoint. 12 | 13 | https://developers.cannabisreports.com/docs/extracts 14 | """ 15 | 16 | __object__ = Extract 17 | __endpoint__ = 'extracts' 18 | -------------------------------------------------------------------------------- /cannabis_reports/apis/flowers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .abstract_product_endpoint import AbstractProductEndpoint 6 | 7 | from ..models.flower import Flower 8 | 9 | 10 | class Flowers(AbstractProductEndpoint): 11 | """This represents the ``Flowers`` Endpoint. 12 | 13 | https://developers.cannabisreports.com/docs/flowers 14 | """ 15 | 16 | __object__ = Flower 17 | __endpoint__ = 'flowers' 18 | -------------------------------------------------------------------------------- /cannabis_reports/apis/producers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from ..models.producer import Producer 6 | 7 | from .abstract_entity_endpoint import AbstractEntityEndpoint 8 | 9 | 10 | class Producers(AbstractEntityEndpoint): 11 | """This represents the ``Producers`` Endpoint. 12 | 13 | https://developers.cannabisreports.com/docs/producers 14 | """ 15 | 16 | __object__ = Producer 17 | __endpoint__ = 'producers' 18 | -------------------------------------------------------------------------------- /cannabis_reports/apis/products.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .abstract_product_endpoint import AbstractProductEndpoint 6 | 7 | from ..models.product import Product 8 | 9 | 10 | class Products(AbstractProductEndpoint): 11 | """This represents the ``Products`` Endpoint. 12 | 13 | https://developers.cannabisreports.com/docs/products 14 | """ 15 | 16 | __object__ = Product 17 | __endpoint__ = 'products' 18 | -------------------------------------------------------------------------------- /cannabis_reports/apis/strains.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .abstract_item_endpoint import AbstractItemEndpoint 6 | 7 | from ..models.seed_company import SeedCompany 8 | from ..models.strain import Strain 9 | 10 | 11 | class Strains(AbstractItemEndpoint): 12 | """This represents the ``Strains`` Endpoint. 13 | 14 | https://developers.cannabisreports.com/docs/strains 15 | """ 16 | 17 | __object__ = Strain 18 | __endpoint__ = 'strains' 19 | 20 | @classmethod 21 | def search(cls, session, query, sort='name', path='search', limit=None): 22 | """Gets products for a given strain with optional sorting. 23 | 24 | Args: 25 | session (requests.sessions.Session): Authenticated session. 26 | query (str): The search query. 27 | sort (str): Snake cased field name to sort on. Prefix with a `-` 28 | for descending. 29 | path (str): The path for the search (eg for ``strains`` it is 30 | ``search`` and for ``extracts`` it is ``type``. 31 | limit (int, optional): Stop after iterating this many pages. 32 | 33 | Returns: 34 | RequestPaginator(output_type=cannabis_reports.models.Extract): 35 | An iterator of parent extracts. 36 | """ 37 | return super(Strains, cls).search(session, query, sort, path, limit) 38 | 39 | @classmethod 40 | def get_seed_company(cls, session, ucpc): 41 | """Get the seed company that was responsible for a cannabis strain. 42 | 43 | Args: 44 | session (requests.sessions.Session): Authenticated session. 45 | ucpc (str): `UCPC `_ for 47 | the cannabis strain you want the seed company from. 48 | 49 | Returns: 50 | cannabis_reports.models.SeedCompany: The seed company that was 51 | responsible for this strain. 52 | """ 53 | return cls( 54 | '/strains/%s/seedCompany' % ucpc, 55 | session=session, 56 | out_type=SeedCompany, 57 | singleton=True, 58 | ) 59 | 60 | @classmethod 61 | def get_genetics(cls, session, ucpc): 62 | """Gets the strains that were the parent material for the strain 63 | with the given UCPC. 64 | 65 | Args: 66 | session (requests.sessions.Session): Authenticated session. 67 | ucpc (str): `UCPC `_ for 69 | the cannabis strain you want the genetics from. 70 | 71 | Returns: 72 | RequestPaginator(output_type=cannabis_reports.models.Strain): 73 | An iterator of parent strains. 74 | """ 75 | return cls( 76 | '/strains/%s/genetics' % ucpc, 77 | session=session, 78 | ) 79 | 80 | @classmethod 81 | def get_children(cls, session, ucpc, limit=None): 82 | """Get the child strains that this one has been bred into. 83 | 84 | Args: 85 | session (requests.sessions.Session): Authenticated session. 86 | ucpc (str): `UCPC `_ for 88 | the cannabis strain you want the children from. 89 | limit (int, optional): Stop after iterating this many pages. 90 | 91 | Returns: 92 | RequestPaginator(output_type=cannabis_reports.models.Strain): 93 | An iterator of child strains. 94 | """ 95 | return cls( 96 | '/strains/%s/children' % ucpc, 97 | session=session, 98 | iteration_limit=limit, 99 | ) 100 | -------------------------------------------------------------------------------- /cannabis_reports/auth_proxy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | 6 | class AuthProxy(object): 7 | """This object acts as a transparent authentication proxy for the API. 8 | 9 | This is required because the API objects are naive of the authentication 10 | that is setup in ``CannabisReports``, and all of the API interface 11 | methods are ``classmethods`` because they are instantiating. 12 | """ 13 | 14 | # These methods will not pass through to ``proxy_class``. 15 | METHOD_NO_PROXY = [ 16 | 'auth_proxy', 17 | ] 18 | 19 | def __init__(self, session, proxy_class): 20 | """Instantiate an API Authentication Proxy. 21 | 22 | Args: 23 | auth (requests.Session): Authenticated requests Session. 24 | proxy_class (type): A class implementing the ``BaseApi`` 25 | interface. 26 | """ 27 | assert isinstance(proxy_class, type) 28 | self.session = session 29 | self.proxy_class = proxy_class 30 | 31 | def __getattr__(self, item): 32 | """Override attribute getter to act as a proxy for``proxy_class``. 33 | 34 | If ``item`` is contained in ``METHOD_NO_PROXY``, it will not be 35 | proxied to the ``proxy_class`` and will instead return the attribute 36 | on this object. 37 | 38 | Args: 39 | item (str): Name of attribute to get. 40 | """ 41 | if item in self.METHOD_NO_PROXY: 42 | return super(AuthProxy, self).__getattr__(item) 43 | attr = getattr(self.proxy_class, item) 44 | if callable(attr): 45 | return self.auth_proxy(attr) 46 | 47 | def auth_proxy(self, method): 48 | """Authentication proxy for API requests. 49 | 50 | This is required because the API objects are naive of 51 | ``CannabisReports``, so they would otherwise be unauthenticated. 52 | 53 | Args: 54 | method (callable): A method call that should be authenticated. It 55 | should accept a ``requests.Session`` as its first parameter, 56 | which should be used for the actual API call. 57 | 58 | Returns: 59 | mixed: The results of the authenticated callable. 60 | """ 61 | def _proxy(*args, **kwargs): 62 | """The actual proxy, which instantiates and authenticates the API. 63 | 64 | Args: 65 | *args (mixed): Args to send to class instantiation. 66 | **kwargs (mixed): Kwargs to send to class instantiation. 67 | 68 | Returns: 69 | mixed: The result of the authenticated callable. 70 | """ 71 | return method(self.session, *args, **kwargs) 72 | 73 | return _proxy 74 | -------------------------------------------------------------------------------- /cannabis_reports/base_api.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .base_model import BaseModel 6 | from .request_paginator import RequestPaginator 7 | 8 | 9 | class BaseApi(object): 10 | """This is the API interface object to be implemented by API adapters. 11 | 12 | It acts as a collection for the API object that it represents, passing 13 | through iteration to the API's request paginator. 14 | 15 | Attributes: 16 | BASE_URI (str): CannabisReports API URI base. 17 | paginator (RequestPaginator): Object to use for producing an iterator 18 | representing multiple requests (API response pages). Created on init. 19 | __object__ (cannabis_reports.models.BaseModel): Model object that API 20 | represents. 21 | """ 22 | 23 | BASE_URI = 'https://www.cannabisreports.com/api/v1.0' 24 | 25 | # This should be replaced in child classes with the correct model. 26 | __object__ = BaseModel 27 | 28 | # This should be replaced with the endpoint, such as ``strains`` 29 | __endpoint__ = None 30 | 31 | # This is set within new, after the object has been created. 32 | paginator = None 33 | 34 | def __new__(cls, endpoint, data=None, 35 | request_type=RequestPaginator.GET, singleton=False, 36 | session=None, out_type=None, iteration_limit=None): 37 | """Create a new API object. 38 | 39 | Args: 40 | endpoint (str): The API endpoint that this represents. 41 | ``BASE_URI`` will be prepended, with no slashes added. 42 | data (dict, optional): Data to send with the request. 43 | request_type (str, optional): Type of request (``GET or ``POST``). 44 | Defaults to ``GET``. 45 | singleton (bool, optional): Set this to ``True`` to assert that 46 | there is not more than one result, and return the first result 47 | (or ``None`` if there is no result). 48 | session (requests.Session, optional): An authenticated requests 49 | session to use. 50 | out_type (BaseModel, optional): If set, this object will be used 51 | for the creation of the models, instead of the one set in 52 | ``cls.__object__``. 53 | iteration_limit (int, optional): Limit of pages that can be 54 | iterated. 55 | 56 | Raises: 57 | CannabisReportsRemoteException: If ``singleton`` is ``True``, but 58 | the remote API responds with more than one result. 59 | 60 | Returns: 61 | BaseApi: An instance of an API object, if ``singleton`` is 62 | ``False``. 63 | BaseModel: An instance of a Model, if ``singleton`` is 64 | ``True`` and there are results. 65 | None: If ``singleton`` is ``True`` and there are no results. 66 | """ 67 | if out_type is None: 68 | out_type = cls.__object__ 69 | paginator = RequestPaginator( 70 | endpoint='%s%s' % (cls.BASE_URI, endpoint), 71 | data=data, 72 | output_type=out_type.from_api, 73 | request_type=request_type, 74 | session=session, 75 | iteration_limit=iteration_limit, 76 | ) 77 | if singleton: 78 | results = paginator.call(paginator.data) 79 | if not results: 80 | return None 81 | return out_type.from_api(**results) 82 | obj = super(BaseApi, cls).__new__(cls) 83 | obj.paginator = paginator 84 | return obj 85 | 86 | def __iter__(self): 87 | """Pass through iteration to the API response.""" 88 | for row in self.paginator: 89 | yield row 90 | raise StopIteration() 91 | 92 | @classmethod 93 | def new_object(cls, data): 94 | """Return a new object of the correct type from the data. 95 | 96 | Args: 97 | data (dict): Data dictionary that should be converted to an 98 | object. It can use either camelCase keys or snake_case. 99 | 100 | Returns: 101 | BaseModel: A model of the type declared in ``cls.__object__``. 102 | """ 103 | return cls.__object__.from_api(**data) 104 | 105 | # Universal endpoints 106 | 107 | @classmethod 108 | def list(cls, session, sort='created_at', descending=False, limit=None): 109 | """Return all objects, with optional sorting. 110 | 111 | Args: 112 | session (requests.sessions.Session): Authenticated session. 113 | sort (str): Column to sort by. One of: 114 | 115 | * ``created_at`` 116 | * ``updated_at`` 117 | * ``name`` 118 | 119 | descending (bool, optional): Set to True to put newest records 120 | at the top. 121 | limit (int, optional): Stop after iterating this many pages. 122 | 123 | Returns: 124 | RequestPaginator(output_type=cls.__object__): 125 | Objects iterator. 126 | """ 127 | sort = BaseModel._to_camel_case(sort) 128 | if descending: 129 | sort = '-%s' % sort 130 | return cls( 131 | '/%s' % cls.__endpoint__, 132 | data={'sort': sort}, 133 | session=session, 134 | iteration_limit=limit, 135 | ) 136 | 137 | @classmethod 138 | def get(cls, session, ucpc): 139 | """Gets an individual object based on the UCPC. 140 | 141 | Args: 142 | session (requests.sessions.Session): Authenticated session. 143 | ucpc (str): `UCPC `_ for 145 | the cannabis object you want information about. 146 | 147 | Returns: 148 | cls.__object__: The object that was found. 149 | """ 150 | return cls( 151 | '/%s/%s' % (cls.__endpoint__, ucpc), 152 | session=session, 153 | singleton=True, 154 | ) 155 | -------------------------------------------------------------------------------- /cannabis_reports/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | 6 | class CannabisReportsException(Exception): 7 | """Base exception for CannabisReports library errors.""" 8 | 9 | def __init__(self, message): 10 | self.message = message 11 | 12 | def __str__(self): 13 | return str(self.message) 14 | 15 | 16 | class CannabisReportsRemoteException(CannabisReportsException): 17 | """Indicates that an error occurred when communicating with the remote.""" 18 | 19 | def __init__(self, status_code, message): 20 | self.status_code = status_code 21 | super(CannabisReportsRemoteException, self).__init__(message) 22 | 23 | def __str__(self): 24 | return '(%d) %s' % (self.status_code, self.message) 25 | 26 | 27 | class CannabisReportsValidationException(CannabisReportsException): 28 | """Indicates an error while validating user-supplied data.""" 29 | 30 | 31 | class CannabisReportsSecurityException(CannabisReportsException): 32 | """Indicates a security error; probably by an invalid web hook signature. 33 | """ 34 | -------------------------------------------------------------------------------- /cannabis_reports/models/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .address import Address 6 | from .dispensary import Dispensary 7 | from .edible import Edible 8 | from .effects_flavors import Effect, EffectsFlavors, Flavor 9 | from .extract import Extract 10 | from .flower import Flower 11 | from .menu_item import MenuItem, MenuItemSummary 12 | from .producer import Producer 13 | from .product import Product 14 | from .review import Review 15 | from .seed_company import SeedCompany 16 | from .strain import Strain, StrainGenetics 17 | from .user import User 18 | 19 | __all__ = [ 20 | 'Address', 21 | 'Dispensary', 22 | 'Edible', 23 | 'Effect', 24 | 'EffectsFlavors', 25 | 'Flavor', 26 | 'Extract', 27 | 'Flower', 28 | 'MenuItem', 29 | 'MenuItemSummary', 30 | 'Producer', 31 | 'Product', 32 | 'Review', 33 | 'SeedCompany', 34 | 'Strain', 35 | 'StrainGenetics', 36 | 'User', 37 | ] 38 | -------------------------------------------------------------------------------- /cannabis_reports/models/abstract_item.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import properties 6 | 7 | from ..base_model import GeneralOverview, LinksModelWithImage 8 | 9 | from .producer import Producer 10 | from .strain import Strain 11 | 12 | 13 | class AbstractItem(LinksModelWithImage): 14 | """Represents the base attributes for a saleable cannabis item.""" 15 | 16 | name = properties.String( 17 | 'Name of the item.', 18 | ) 19 | barcode = properties.String( 20 | 'Link to the barcode for this item.', 21 | ) 22 | producer = properties.Instance( 23 | 'Information about the producer that created the item.', 24 | instance_class=Producer, 25 | ) 26 | type = properties.String( 27 | 'Type of item.', 28 | ) 29 | strain = properties.Instance( 30 | 'Strain that this item comes from.', 31 | instance_class=Strain, 32 | ) 33 | lab_test = properties.String( 34 | 'Link to the PDF containing lab test information for this item.', 35 | ) 36 | thc = properties.String( 37 | 'Amount of `THC `_ in this ' 39 | 'item.', 40 | ) 41 | cbd = properties.String( 42 | 'Amount of `CBD `_ in this item.', 44 | ) 45 | cannabis = properties.String( 46 | 'Milligrams of cannabis in this item.', 47 | ) 48 | hash_oil = properties.String( 49 | 'Milligrams of hash oil in this item.', 50 | ) 51 | reviews = properties.Instance( 52 | 'Object containing information on the reviews for the item.', 53 | instance_class=GeneralOverview, 54 | ) 55 | -------------------------------------------------------------------------------- /cannabis_reports/models/address.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import properties 6 | 7 | from ..base_model import BaseModel 8 | 9 | 10 | class Address(BaseModel): 11 | """Object containing address location information.""" 12 | 13 | address_1 = properties.String( 14 | 'Street address.', 15 | ) 16 | address_2 = properties.String( 17 | 'Additional street address line.', 18 | ) 19 | zip = properties.String( 20 | 'Zip Code.', 21 | ) 22 | -------------------------------------------------------------------------------- /cannabis_reports/models/dispensary.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import properties 6 | 7 | from ..base_model import GeneralOverview, LinksModelWithImage 8 | 9 | from .address import Address 10 | 11 | 12 | class Dispensary(LinksModelWithImage): 13 | """Cannabis producers are the ones that create all of the cannabis flowers, 14 | extracts, edibles, and other products we know and love. 15 | 16 | More information about cannabis producers can be found in the `Cannabis 17 | Reports FAQ `_. 19 | """ 20 | 21 | name = properties.String( 22 | 'Name of the dispensary.', 23 | ) 24 | state = properties.String( 25 | 'Two character representation of the state this dispensary is in.', 26 | ) 27 | city = properties.String( 28 | 'City this dispensary is in.', 29 | ) 30 | lat = properties.String( 31 | 'Latitude of this dispensary.', 32 | ) 33 | lng = properties.String( 34 | 'Longitude of this dispensary.', 35 | ) 36 | address = properties.Instance( 37 | 'Object containing additional location information for this ' 38 | 'dispensary.', 39 | instance_class=Address, 40 | ) 41 | slug = properties.String( 42 | 'Identifier for this dispensary; a combination of city and state.', 43 | ) 44 | reviews = properties.Instance( 45 | 'The number of reviews for all of the strains available from this ' 46 | 'seed Producer.', 47 | instance_class=GeneralOverview, 48 | ) 49 | strains = properties.Instance( 50 | 'Object containing information about strains available at this ' 51 | 'dispensary.', 52 | instance_class=GeneralOverview, 53 | ) 54 | extracts = properties.Instance( 55 | 'Information on all of the extracts that this producer makes.', 56 | instance_class=GeneralOverview, 57 | ) 58 | edibles = properties.Instance( 59 | 'Information on all of the edibles that this producer makes.', 60 | instance_class=GeneralOverview, 61 | ) 62 | products = properties.Instance( 63 | 'Information on all of the products that this producer makes.', 64 | instance_class=GeneralOverview, 65 | ) 66 | -------------------------------------------------------------------------------- /cannabis_reports/models/edible.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .abstract_item import AbstractItem 6 | 7 | 8 | class Edible(AbstractItem): 9 | """Cannabis edibles cover a wide variety of consumable products that 10 | contain cannabis in various forms. From cotton candy, to tinctures, 11 | to dog treats, and everything in between. 12 | 13 | If it's a form of cannabis that is meant to be consumed, it is 14 | categorized as an edible. 15 | 16 | The main forms of edibles that Cannabis Reports recognizes are: 17 | 18 | * `Baked Goods `_ 20 | * `Candy `_ 21 | * `Treat `_ 22 | * `Chocolate `_ 23 | * `Snack `_ 24 | * `Beverage `_ 25 | * `Pill `_ 26 | * `Tincture `_ 27 | 28 | Cannabis Reports also supports "Other" types of edibles. Some examples 29 | are: 30 | 31 | * Butter 32 | * Honey 33 | * Breath Strips 34 | * Tea 35 | * Ice Cream 36 | 37 | Producers measure the amount of cannabis in their edibles in a variety of 38 | ways. We recognize 4 ways for measuring the cannabis contents: 39 | 40 | * THC mg 41 | * CBD mg 42 | * Cannabis mg 43 | * Hash Oil mg 44 | 45 | More information about cannabis edibles can be found in the `FAQ 46 | `_. 48 | """ 49 | -------------------------------------------------------------------------------- /cannabis_reports/models/effects_flavors.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import properties 6 | 7 | from ..base_model import BaseModel 8 | 9 | 10 | class Effect(BaseModel): 11 | """Represents an effect profile.""" 12 | 13 | euphoria = properties.Float( 14 | 'Euphoric effect.', 15 | default=0.0, 16 | ) 17 | creativity = properties.Float( 18 | 'Creativity effect', 19 | default=0.0, 20 | ) 21 | calming = properties.Float( 22 | 'Calming effect', 23 | default=0.0, 24 | ) 25 | numbness = properties.Float( 26 | 'Numbness effect', 27 | default=0.0, 28 | ) 29 | appetite_gain = properties.Float( 30 | 'Appetite gain effect', 31 | default=0.0, 32 | ) 33 | dry_mouth = properties.Float( 34 | 'Dry mouth effect', 35 | default=0.0, 36 | ) 37 | anxiety = properties.Float( 38 | 'Anxiety effect', 39 | default=0.0, 40 | ) 41 | 42 | 43 | class Flavor(BaseModel): 44 | """Represents a flavor profile.""" 45 | 46 | fruity = properties.Float( 47 | 'Fruity flavor', 48 | default=0.0, 49 | ) 50 | spicy = properties.Float( 51 | 'Spicy flavor', 52 | default=0.0, 53 | ) 54 | earthy = properties.Float( 55 | 'Earthy flavor', 56 | default=0.0, 57 | ) 58 | sour = properties.Float( 59 | 'Sour flavor', 60 | default=0.0, 61 | ) 62 | sweet = properties.Float( 63 | 'Sweet flavor', 64 | default=0.0, 65 | ) 66 | pine = properties.Float( 67 | 'Pine flavor', 68 | default=0.0, 69 | ) 70 | 71 | 72 | class EffectsFlavors(Effect, Flavor): 73 | """Represents a flavor and effect profile.""" 74 | -------------------------------------------------------------------------------- /cannabis_reports/models/extract.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .abstract_item import AbstractItem 6 | 7 | 8 | class Extract(AbstractItem): 9 | """Cannabis extracts are created from the flowers of the cannabis plant. 10 | 11 | Various methods for creating cannabis extracts have been perfected over 12 | thousands of years. 13 | 14 | Cannabis Reports recognizes 10 main types of extracts: 15 | 16 | * `Kief `_ 17 | * `Hash `_ 18 | * `Water-Hash `_ 20 | * `Oil `_ 21 | * `Wax `_ 22 | * `Crumble `_ 23 | * `Honeycomb `_ 24 | * `Shatter `_ 25 | * `Vaporizer-Disposable `_ 27 | * `Vaporizer-Cartridge `_ 29 | 30 | Each extract is tied to a strain and the producer who created it. For more 31 | information about cannabis extracts, check out the `FAQ 32 | `_ 34 | """ 35 | -------------------------------------------------------------------------------- /cannabis_reports/models/flower.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .abstract_item import AbstractItem 6 | 7 | 8 | class Flower(AbstractItem): 9 | """Cannabis flowers are distinct products that can be found on retailer 10 | menus. 11 | 12 | The Cannabis Reports system allows for specific batches of cannabis 13 | flowers to be linked directly to the cultivator that grew the plant, 14 | while still maintaining a connection to the original genetics of the 15 | strain. 16 | 17 | Designating flowers as distinct items improves our ability to discuss 18 | the variety of flower quality that can be produced from the same strain 19 | grown at different farms. 20 | 21 | The main forms of flowers that Cannabis Reports recognizes are: 22 | 23 | * `Flowers `_ 24 | * `Seeds `_ 25 | * `Clones `_ 26 | * `Shake `_ 27 | 28 | Producers measure the cannabinoid content of their flowers in many ways. 29 | Currently, Cannabis Reports allows producers to display the percentage 30 | of weight for THC and CBD. 31 | """ 32 | -------------------------------------------------------------------------------- /cannabis_reports/models/menu_item.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import properties 6 | 7 | from ..base_model import BaseModel 8 | 9 | from .dispensary import Dispensary 10 | 11 | 12 | class MenuItem(BaseModel): 13 | """Menu items for dispensaries.""" 14 | 15 | name = properties.String( 16 | 'Name of the item.', 17 | ) 18 | type = properties.StringChoice( 19 | 'Type of item.', 20 | choices=['strain', 'flower', 'extract', 'edible', 'product'], 21 | ) 22 | item = properties.Property( 23 | 'The strain, extract, edible, or product.', 24 | ) 25 | price = properties.Float( 26 | 'The price for the item. This is not set for strains and extracts.', 27 | ) 28 | price_half_gram = properties.Float( 29 | 'Price for one half gram of the item. This is not set for edibles ' 30 | 'and products.', 31 | ) 32 | price_gram = properties.Float( 33 | 'Price for one gram of this item. This is not set for edibles and ' 34 | 'products.', 35 | ) 36 | price_eighth = properties.Float( 37 | 'Price for one eighth ounce of this item. This is not set for ' 38 | 'edibles and products.', 39 | ) 40 | price_quarter = properties.Float( 41 | 'Price for one quarter ounce of this item. This is not set for ' 42 | 'edibles and products.', 43 | ) 44 | price_half_ounce = properties.Float( 45 | 'Price for one half ounce of this item. This is not set for ' 46 | 'edibles and products.', 47 | ) 48 | price_ounce = properties.Float( 49 | 'Price for one ounce of this item. This is not set for ' 50 | 'edibles and products.', 51 | ) 52 | 53 | 54 | class MenuItemSummary(MenuItem): 55 | """Menu item summary for when it is known what the menu item is.""" 56 | 57 | location = properties.Instance( 58 | 'Object containing information about the location this item is at.', 59 | instance_class=Dispensary, 60 | ) 61 | -------------------------------------------------------------------------------- /cannabis_reports/models/producer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import properties 6 | 7 | from ..base_model import GeneralOverview, LinksModelWithImage 8 | 9 | 10 | class Producer(LinksModelWithImage): 11 | """Cannabis producers are the ones that create all of the cannabis flowers, 12 | extracts, edibles, and other products we know and love. 13 | 14 | More information about cannabis producers can be found in the `Cannabis 15 | Reports FAQ `_. 17 | """ 18 | 19 | name = properties.String( 20 | 'The name of the producer.', 21 | ) 22 | reviews = properties.Instance( 23 | 'The number of reviews for all of the strains available from this ' 24 | 'seed Producer.', 25 | instance_class=GeneralOverview, 26 | ) 27 | extracts = properties.Instance( 28 | 'Information on all of the extracts that this producer makes.', 29 | instance_class=GeneralOverview, 30 | ) 31 | edibles = properties.Instance( 32 | 'Information on all of the edibles that this producer makes.', 33 | instance_class=GeneralOverview, 34 | ) 35 | products = properties.Instance( 36 | 'Information on all of the products that this producer makes.', 37 | instance_class=GeneralOverview, 38 | ) 39 | -------------------------------------------------------------------------------- /cannabis_reports/models/product.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .abstract_item import AbstractItem 6 | 7 | 8 | class Product(AbstractItem): 9 | """Cannabis products cover a wide variety of additional products that 10 | contain cannabis. 11 | 12 | Anything that wouldn't be consumed like an product or extract falls into 13 | this category. Pre-rolled cannabis is also in this category. 14 | 15 | The main forms of products that Cannabis Reports recognizes are: 16 | 17 | * `Bath `_ 18 | * `Topical `_ 19 | * `Skin Care `_ 20 | * `Pre-Roll `_ 21 | 22 | Cannabis Reports also supports "Other" types of products. Some examples 23 | are: 24 | 25 | * Lip Balm 26 | * Massage Oil 27 | * Personal Lubricant 28 | 29 | Producers measure the amount of cannabis in their products in a variety of 30 | ways. We recognize 4 ways for measuring the cannabis contents: 31 | 32 | * THC mg 33 | * CBD mg 34 | * Cannabis mg 35 | * Hash Oil mg 36 | 37 | More information about cannabis products can be found in the `FAQ 38 | `_. 40 | """ 41 | -------------------------------------------------------------------------------- /cannabis_reports/models/review.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from ..base_model import BaseModelWithLinks 6 | 7 | from .effects_flavors import EffectsFlavors 8 | 9 | 10 | class Review(BaseModelWithLinks, EffectsFlavors): 11 | """Represents a CannabisReports review.""" 12 | -------------------------------------------------------------------------------- /cannabis_reports/models/seed_company.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import properties 6 | 7 | from ..base_model import GeneralOverview, LineageModel 8 | 9 | 10 | class SeedCompany(LineageModel): 11 | """Cannabis seed companies create the variety of strains available for 12 | growing and breeding. 13 | """ 14 | 15 | name = properties.String( 16 | 'The name of this seed company.', 17 | ) 18 | strains = properties.Instance( 19 | 'Object containing information on the strains available from this ' 20 | 'seed company.', 21 | instance_class=GeneralOverview, 22 | ) 23 | reviews = properties.Instance( 24 | 'The number of reviews for all of the strains available from this ' 25 | 'seed company.', 26 | instance_class=GeneralOverview, 27 | ) 28 | -------------------------------------------------------------------------------- /cannabis_reports/models/strain.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import properties 6 | 7 | from ..base_model import BaseModel, GeneralOverview, LineageModel 8 | 9 | from .seed_company import SeedCompany 10 | 11 | 12 | class StrainGenetics(BaseModel): 13 | """Object that holds information about the genetics for the strain.""" 14 | 15 | names = properties.String( 16 | 'Genetics name. `More information `_.', 18 | ) 19 | link = properties.String( 20 | 'Link to the genetic listing in the Cannabis Reports API.', 21 | ) 22 | 23 | 24 | class Strain(LineageModel): 25 | """Cannabis strains are the various cultivars available for the cannabis 26 | family. Thousands of years of human domestication and breeding of cannabis 27 | strains have resulted in a huge variety of attributes that we know and 28 | love today. 29 | 30 | `Wikipedia Definition `_ 31 | 32 | Over time, strain names have been used by various companies in their 33 | attempts to recreate the results of other breeders. Cannabis Reports 34 | identifies strains not only by their name, but by their seed company as 35 | well, to ensure they are all properly represented. 36 | """ 37 | 38 | name = properties.String( 39 | 'Name of the cannabis strain.', 40 | ) 41 | seed_company = properties.Instance( 42 | 'Information about the seed company that created or provides the ' 43 | 'strain.', 44 | instance_class=SeedCompany, 45 | ) 46 | genetics = properties.Instance( 47 | 'Object that holds information about the genetics for the strain.', 48 | instance_class=StrainGenetics, 49 | ) 50 | children = properties.Instance( 51 | 'Object that holds information about the children for the strain.', 52 | instance_class=GeneralOverview, 53 | ) 54 | reviews = properties.Instance( 55 | 'Object that holds information about the reviews for the strain.', 56 | instance_class=GeneralOverview, 57 | ) 58 | -------------------------------------------------------------------------------- /cannabis_reports/models/user.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import properties 6 | 7 | from ..base_model import BaseModelWithLinks 8 | 9 | 10 | class User(BaseModelWithLinks): 11 | """Represents a CannabisReports user.""" 12 | 13 | nickname = properties.String( 14 | 'The user nickname.', 15 | ) 16 | tagline = properties.String( 17 | 'The user tagline.', 18 | ) 19 | slug = properties.String( 20 | 'The user slug.', 21 | ) 22 | -------------------------------------------------------------------------------- /cannabis_reports/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | -------------------------------------------------------------------------------- /cannabis_reports/tests/api_common.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import unittest 6 | 7 | from os.path import dirname, join 8 | 9 | from vcr import VCR 10 | 11 | from .. import CannabisReports 12 | 13 | 14 | recorder = VCR( 15 | record_mode='once', 16 | cassette_library_dir=join(dirname(__file__), 'fixtures/cassettes'), 17 | path_transformer=VCR.ensure_suffix('.yml'), 18 | filter_headers=['X-API-Key'], 19 | ) 20 | 21 | 22 | class ApiCommon(unittest.TestCase): 23 | 24 | LIMIT_LIST = 10 25 | LIMIT_PAGE = 2 26 | 27 | # Subclasses must define this, such as ``self.api.Edibles`` 28 | endpoint = None 29 | # Subclasses must define this, typically a UCPC 30 | UID = None 31 | 32 | def setUp(self): 33 | super(ApiCommon, self).setUp() 34 | self.api = CannabisReports() 35 | 36 | def _test_apis_objects_list(self, expect_class): 37 | """It should parse the response and return the proper object.""" 38 | result_count = 0 39 | for result in self.endpoint.list(limit=self.LIMIT_PAGE): 40 | self.assertIsInstance(result, expect_class) 41 | result_count += 1 42 | self.assertEqual(result_count, self.LIMIT_LIST * self.LIMIT_PAGE) 43 | 44 | def _test_apis_objects_get(self, expect_name): 45 | """It should return the proper singleton.""" 46 | result = self.endpoint.get(self.UID) 47 | self.assertEqual(result.name, expect_name) 48 | -------------------------------------------------------------------------------- /cannabis_reports/tests/api_entity.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .api_common import ApiCommon 6 | 7 | from ..models.edible import Edible 8 | from ..models.extract import Extract 9 | from ..models.menu_item import MenuItemSummary 10 | from ..models.product import Product 11 | from ..models.strain import Strain 12 | 13 | 14 | class ApiEntityAbstract(ApiCommon): 15 | """Tests the AbstractEntityEndpoint API endpoints.""" 16 | 17 | def _test_apis_objects_get_extracts(self): 18 | extracts = self.endpoint.get_extracts( 19 | self.UID, limit=self.LIMIT_PAGE, 20 | ) 21 | got_results = False 22 | for extract in extracts: 23 | self.assertIsInstance(extract, Extract) 24 | got_results = True 25 | self.assertTrue(got_results) 26 | 27 | def _test_apis_objects_get_edibles(self): 28 | edibles = self.endpoint.get_edibles( 29 | self.UID, limit=self.LIMIT_PAGE, 30 | ) 31 | got_results = False 32 | for edible in edibles: 33 | self.assertIsInstance(edible, Edible) 34 | got_results = True 35 | self.assertTrue(got_results) 36 | 37 | def _test_apis_objects_get_products(self): 38 | products = self.endpoint.get_products( 39 | self.UID, limit=self.LIMIT_PAGE, 40 | ) 41 | got_results = False 42 | for product in products: 43 | self.assertIsInstance(product, Product) 44 | got_results = True 45 | self.assertTrue(got_results) 46 | 47 | def _test_apis_objects_get_strains(self): 48 | strains = self.endpoint.get_strains( 49 | self.UID, limit=self.LIMIT_PAGE, 50 | ) 51 | got_results = False 52 | for strain in strains: 53 | self.assertIsInstance(strain, Strain) 54 | got_results = True 55 | self.assertTrue(got_results) 56 | 57 | def _test_apis_objects_get_available(self): 58 | """It should return the menu items.""" 59 | available = self.endpoint.get_available( 60 | self.UID, 37.7749295, -122.4194155, limit=self.LIMIT_PAGE, 61 | ) 62 | got_results = False 63 | for available in available: 64 | self.assertIsInstance(available, MenuItemSummary) 65 | got_results = True 66 | self.assertTrue(got_results) 67 | -------------------------------------------------------------------------------- /cannabis_reports/tests/api_product.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .api_common import ApiCommon 6 | 7 | from ..models.menu_item import MenuItemSummary 8 | from ..models.review import Review 9 | 10 | 11 | class ApiProductAbstract(ApiCommon): 12 | """Tests the AbstractProductEndpoint API endpoints.""" 13 | 14 | def _test_apis_objects_get_user(self, expect_name): 15 | """It should return the proper user singleton.""" 16 | user = self.endpoint.get_user(self.UID) 17 | self.assertEquals(user.nickname, expect_name) 18 | 19 | def _test_apis_objects_get_review(self): 20 | """It should return the reviews.""" 21 | reviews = self.endpoint.get_reviews(self.UID) 22 | got_results = False 23 | for review in reviews: 24 | self.assertIsInstance(review, Review) 25 | got_results = True 26 | self.assertTrue(got_results) 27 | 28 | def _test_apis_objects_get_effects_flavors(self, attribute='euphoria'): 29 | """It should return the effect & flavor profile.""" 30 | effect_flavor = self.endpoint.get_effects_flavors(self.UID) 31 | self.assertGreater(getattr(effect_flavor, attribute), 0) 32 | 33 | def _test_apis_objects_get_available(self): 34 | """It should return the menu items.""" 35 | available = self.endpoint.get_available( 36 | self.UID, 37.7749295, -122.4194155, 37 | ) 38 | got_results = False 39 | for available in available: 40 | self.assertIsInstance(available, MenuItemSummary) 41 | got_results = True 42 | self.assertTrue(got_results) 43 | 44 | def _test_apis_objects_search(self, query, expect_class): 45 | """It should parse the response and return the proper objects.""" 46 | result_count = 0 47 | results = self.endpoint.search(query, limit=self.LIMIT_PAGE) 48 | for result in results: 49 | self.assertIsInstance(result, expect_class) 50 | result_count += 1 51 | self.assertEqual(result_count, self.LIMIT_LIST * self.LIMIT_PAGE) 52 | 53 | def _test_apis_objects_get_producer(self, expect_name): 54 | """It should return the producer.""" 55 | producer = self.endpoint.get_producer(self.UID) 56 | self.assertEqual(producer.name, expect_name) 57 | 58 | def _test_apis_objects_get_strain(self, expect_name): 59 | """It should return the strain.""" 60 | strain = self.endpoint.get_strain(self.UID) 61 | self.assertEqual(strain.name, expect_name) 62 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_dispensaries_get.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/dispensaries/ca/san-francisco/grass-roots?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7yUTW/cIBBA/4o1Z2zAxl/cokjttWraG1KFMbul9YIDONsk8n+vWO2mG6lVcqlv 15 | CGbmPc2MeIZRRgn8Gaw8aODw0csQss/OxQAIJmN/AofvMc6BCyzw8XgslLRWDiZ4PTsfQ6HcQWA5 16 | G4EfaEEEHk2YtQ3SGx0EVlLgIG2+89IqE5QTeJ8YuT8z7v37CC9lH/Pz/VvFBb73uXKjBgSLn/4X 17 | BhCYg9zr99U/hQaBZ+92ZtIC1wLvlmn6Vrcl2RFGGSUD7VjXDY1mQ18qIiul674btKq07Iof8x4Q 18 | hChjQt7eAAJl4iNwuJM2+3BxTDHTsgcOb+pPMgKHqi3arml6RtOVTZk5LcuC0Z6VfQUI5Dh6HUJa 19 | l/ORAgdK2jb75ELM7qLXOv4JLIEDIHgyM3DoGSU9rAi8fjD6eKqi3GIj8LrfYNUEvoDX1D0vjb12 20 | IJsoXLgrgt3kjtpfK5R0E4cLeEWgf0UvVXw1i00cXsBJYjTDpK8d2EYSZ/CKYPZuXF43YpthvIBX 21 | BMprGfV4E5PFKKOO5vQnl4TWOWlywjLacNbzqgYE6fHJ2RTw9cttyl/m8V/5bU76nNKMNLwqOan+ 22 | kr+uvwEAAP//AwABR8j4DQYAAA== 23 | headers: 24 | CF-RAY: [3cab2da7ceef5f8d-LAS] 25 | Cache-Control: ['private, must-revalidate'] 26 | Connection: [keep-alive] 27 | Content-Encoding: [gzip] 28 | Content-Type: [application/json] 29 | Date: ['Sat, 09 Dec 2017 21:50:09 GMT'] 30 | ETag: [W/"18d50e8fd1a7bd5b5e632369c39d3975-gzip"] 31 | Server: [cloudflare-nginx] 32 | Set-Cookie: ['__cfduid=d4aa8e65a2c1c470c6daaf15ca92d8d771512856208; expires=Sun, 33 | 09-Dec-18 21:50:08 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 34 | 'XSRF-TOKEN=eyJpdiI6InBFVjdUQW1iVWdObWd2R1lGT1BjNGc9PSIsInZhbHVlIjoiaHdGRVZ6UjRneGRZSG1NSlRJaXU0MW02eWt1YXlvV0tweVNWMFZzQkZzWXVnRWN0QVYzcE4zaHA0czh5NE5GTCtjMHBlK0ZyMTdQMDFQTFRGUGlcL3B3PT0iLCJtYWMiOiJlNTczN2ZmOGUxZmNiMDcwNzMwMDNhOGMyMzlmZTk1NzYyMjFiMmJjNmJlNGUwYmYyZDUxOTEyMWZiMzQyYmUyIn0%3D; 35 | expires=Sat, 09-Dec-2017 23:50:09 GMT; Max-Age=7200; path=/'] 36 | Vary: [Accept-Encoding] 37 | X-RateLimit-Limit: ['25'] 38 | X-RateLimit-Remaining: ['14'] 39 | X-RateLimit-Reset: ['1512857051'] 40 | status: {code: 200, message: OK} 41 | version: 1 42 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_dispensaries_get_available.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/dispensaries/ca/san-francisco/grass-roots/availability/geo/37.7749295/-122.4194155/10?page=1 11 | response: 12 | body: {string: '{"message":"404 Not Found","status_code":404}'} 13 | headers: 14 | CF-RAY: [3cab2c416f9d5f51-LAS] 15 | Cache-Control: [no-cache] 16 | Connection: [keep-alive] 17 | Content-Length: ['45'] 18 | Content-Type: [application/json] 19 | Date: ['Sat, 09 Dec 2017 21:49:11 GMT'] 20 | Server: [cloudflare-nginx] 21 | Set-Cookie: ['__cfduid=d529da6c1c30ea30392b1f419b5cd94e71512856151; expires=Sun, 22 | 09-Dec-18 21:49:11 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 23 | 'XSRF-TOKEN=eyJpdiI6IjE4MEVmVkRGMG00RWF5aGtPSWJtZWc9PSIsInZhbHVlIjoiTTZKS3lXNmdnMjB1dmFnZzl4UVJPbWhGZVZHcjM0SUJOOUkxbklBY285TVhFeENPWXJMZHNoNm9TaWpHSnZQaGtxNDZKa1VqSDMrQnZRM3Jzakl6Zmc9PSIsIm1hYyI6ImVmYWMxMzI3YjVjMzEzMWY3MzFkZDE0YzRkYTAzMmE4OTFjYmNmZGM3MjhiYjQxMWUzNGFiODMwYmY5OTQ3NzAifQ%3D%3D; 24 | expires=Sat, 09-Dec-2017 23:49:11 GMT; Max-Age=7200; path=/'] 25 | status: {code: 404, message: Not Found} 26 | version: 1 27 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_dispensaries_get_extracts.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/dispensaries/ca/san-francisco/grass-roots/extracts?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA+yaXW+jOBSG/wqytHcQjDEf9l22s7OzrXYuRu1MZodRZYydsCVAjdNP5b+PSEhm 15 | 0iVJS5psVdVX2Pi8Pj6c40cg7kHCNAP02z3I2VgACn7PJiIWSt0aH9idMCzjMysLld4JZRwxpVWa 16 | DAUwgb4t69niRivGNTBBqsUY0KfKTHjJAQWnp2dfP346G/jk/bu+/wUdHX35CusGTJCl+QWgYKR1 17 | WdHIjuzr6+seZ3nO4rRSoiyUrnq8GEc2K9PIvnJ6MLIbv6rI3iR9qR4n3KhZzWBkXyqLF4mI7Dgr 18 | irElmRpXkZ3kzBqKXOiUV/WtJgLWiN2JyL5aBMDiiwD0ynwITBAzVat19KWxfiZfJirr6sdOy9cZ 19 | NGbDRwZhNrX69THzyJaTLDvnsSsxg5hAguI4xCwgIXHiAKEAYeYFnCdYMox6/5b1dktVJBMu1Erm 20 | FsXYeF/v42eCwmWbZdHPbtcEXSxcRfZ67emyzpYRM36NWKUVS/O1VddWX3C1dXV/vvJKeT1Unpog 21 | Y/GpqDSgkmWVMIEe8eU1j5PltRJXqbiu6o3wYpJrQOH+6j6yF8tNTcCVYFokfV2vnTAtdDoLJIKO 22 | b0HfgoHhhNTDFLv1oZeOxV2R1xPOTo9q+0mZbLAnFgwNJ6AupMhvsZ/WCZhyAWg+ybKmcz5imTwf 23 | Kjau8643e0bzG21jIh2O9GhV4HLClK5z+j+qxSR/uNrK0GPCQSh0qOd3CMc2+6m5TOS/8qpMVXf8 24 | bLNv6oIMPp8Ff/59enJ08s9x/8Q/Pv54/Ezc2SS9O3dYxkdifGvFt1bC1IU1EkzpyM4Lbc1L06pK 25 | wVOZ8shO57E4AIGe2avuLHouR3alUtBQKXCkhNz1oZ940k0gE56LHARDyJjnQigJgoLzDVTqz3dk 26 | xLfGO6YujA/1jtr4NMu2PfHpofaT+dSUZVsBPjeY1iuvAxNw4W9g/2BaezA8AUzIcpCBEHUI9Zwd 27 | wYQ6gQm3kQn/b2hy6w0hSD2PumEnNDnQQA5FhLp4M5r+uCmzYgc0bbNvR1MfD9BgP2hakT4smsQ8 28 | Fi8MTY/w6jBo2uTIrmjCDZqw53EoEieIMZcsgTyGrkNEKJjkiSSCu54MHEReO5qasnxDU9vB0AFN 29 | iFCM3tC0gibk74gmtBlN/Wt2IfLOZNpi3g6mAfL7Z/sB04r0YcHEZqF4YVza7tRhsLTBj12pRBoq 30 | EZeFJMScxy4LAuhJL3A8FAeS+D7BIeGeRBA78rVTaV6SLxNKB/qQt/ZQeCqU6g95IYVvUHoAJbgj 31 | lMLNUPokMnbTmUmbrduRdEIGvr8fJK1IHxZJqo7ECyPSVp8OA6T1buzKI9nwSMbYI67wZBCjwOfc 32 | CxmPWYgIxkhAHMvAEciD/mvn0awc396R2g6ELu9IPsXhG45WcOS4O+KozX763QRjUf/ocA9KNkxz 33 | ptNilte60CwD1DMXGeKZoBTqvJwdGg40AZ8oJXK9GDHnJrNuNevXCVUB+u37dDr9AQAA//8DAFEH 34 | LWJQIQAA 35 | headers: 36 | CF-RAY: [3cab2dab7cf05f3f-LAS] 37 | Cache-Control: ['private, must-revalidate'] 38 | Connection: [keep-alive] 39 | Content-Encoding: [gzip] 40 | Content-Type: [application/json] 41 | Date: ['Sat, 09 Dec 2017 21:50:09 GMT'] 42 | ETag: [W/"f12f8dfc69defc9ecc5456fa2b6ecd27-gzip"] 43 | Server: [cloudflare-nginx] 44 | Set-Cookie: ['__cfduid=d56f17e11317f30c6c2fdc07fdc47c12a1512856209; expires=Sun, 45 | 09-Dec-18 21:50:09 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 46 | 'XSRF-TOKEN=eyJpdiI6IkVDYWo0cDB5QXhVMDZ4bjNoMnpxN3c9PSIsInZhbHVlIjoiK2Vkc3IxWHJ5UWN2c1QwMXlwMEF4NVdadU9vblNMYWkxM1NGbDUxQVkwR2t3ZG5tZm9kRW9qSFZ4SVRHVHUyRHZVSlIxM1B0R1k0V3dxVHBjRVpuTkE9PSIsIm1hYyI6ImEwNWI0MGE0MjdmNzgwMjRiZmQwMWIzN2MxMjE5NTg5N2Y2YTcxZjk1ZDk2MmM4N2Y5YzUwMmUwMjFhOTBiZWQifQ%3D%3D; 47 | expires=Sat, 09-Dec-2017 23:50:09 GMT; Max-Age=7200; path=/'] 48 | Vary: [Accept-Encoding] 49 | X-RateLimit-Limit: ['25'] 50 | X-RateLimit-Remaining: ['13'] 51 | X-RateLimit-Reset: ['1512857051'] 52 | status: {code: 200, message: OK} 53 | version: 1 54 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_dispensaries_get_products.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/dispensaries/ca/san-francisco/grass-roots/products?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7RUXWvbMBT9K+Y+bSDFUrKkid7KYA+hYWVkhVGVoMhqrMSWFUlu2Ir/e5Hz0ZSu 15 | Xxnzk85B5557pSPfQyaCAHZ9D0aUChjQbnIp5CqZaKOTS6dKXZcJjivsqqIABOG3jRutq7JaBkCg 16 | gyqBfaBCLa0EBuTwfZtcXF1NLs5//GohICi0WQGDPATrGU95utlsOlIYI+baO2UrF3xHViVPhdU8 17 | vaMdwtNdS56nr5Veu/cV3lXDO5Kna4dllSmeLpdLHJy2hcJLntIutkKucKmNxnY7b8eaBSCYCxcV 18 | J/rt1B/wq11xotfbFvGiS7F45zDtVs9TH5zQxvPUVLOW23W6bUC5o9yMx+Pk07TtIRl/fjEmj/Df 19 | YqLc85wc1W6Ogn4I7nYaYNc3CAoxnyofgN2KwisEIZeHtZxnj+tdNwciFz7/rosDdupOq42PJyGr 20 | 2gRg5P/ln6d7uwaBdEoElZ2H6J2JoIJub6JLaB9TiukoIQPWO2OkH9+9LtWfysQNP6dfo7622Uv6 21 | ASYjTIYJPWM9wvqjv+ibmAItI/5COu11tniWi+J2tnCiBGbqotjTzxmlF3nIn3LrWrgQc3VMthWr 22 | 2kSzY/4J9cppDDDpYzpMul3W67Pe8ITTeEvf3CAoVfwX34MVC21E0JWJKFRBFMAo2seDIrDKzWz7 23 | GClBIGvnlAl7Bm0lLfQtjmnyMbZN0zwAAAD//wMAJJRwtfMFAAA= 24 | headers: 25 | CF-RAY: [3cab2c4f6bb85f63-LAS] 26 | Cache-Control: ['private, must-revalidate'] 27 | Connection: [keep-alive] 28 | Content-Encoding: [gzip] 29 | Content-Type: [application/json] 30 | Date: ['Sat, 09 Dec 2017 21:49:13 GMT'] 31 | ETag: [W/"e5c21456b53c5daf5f451b48221b72ad-gzip"] 32 | Server: [cloudflare-nginx] 33 | Set-Cookie: ['__cfduid=ddb7e7f8c0ecd823614387d229b5001e91512856153; expires=Sun, 34 | 09-Dec-18 21:49:13 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 35 | 'XSRF-TOKEN=eyJpdiI6IjBZUnhVeVwvNm41cktpM0lETEZVeldBPT0iLCJ2YWx1ZSI6ImxGRHJqYmxWbEtqVFhWN0FndnUyc09kRjRSRE4xdGRmYitMY0MrUGs5UlNsWTVka1dOazJpQkg3cXZ5K2lqcTdcL3A3Y1B2QTI0Z3Y1M3AwUUNNbUNwdz09IiwibWFjIjoiYjAyNWVhZTA0ODM2NjM4MWMwNjFmYzU1MDY4MzYyMjAyOTkzMDdlYzdjNzY3OTI5ZWFiNDllYWRkMWEzY2RlZSJ9; 36 | expires=Sat, 09-Dec-2017 23:49:13 GMT; Max-Age=7200; path=/'] 37 | Vary: [Accept-Encoding] 38 | X-RateLimit-Limit: ['25'] 39 | X-RateLimit-Remaining: ['19'] 40 | X-RateLimit-Reset: ['1512857051'] 41 | status: {code: 200, message: OK} 42 | version: 1 43 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_edibles_get.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/edibles/4KXM32V9YFC3G2EUNWP400000?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7RTy27bMBD8FWHPoklbTuPwVhhtDkEfQJKmBQgUK5K1CEukQlIW2kD/XtAPJUXj 15 | IjHQvXHJ2ZlZjR5AYUTgD2Cx0cDh2inMSHZpfJ1dS9fFbOnc2uiQoVXZ0mtsIIdOthI4zK++fihm 16 | Xy6+vV8Wl7N3tx/vPs9ZKsihNnYNHKoY28AFFbTv+4lEa7E0wevW+Rgm0jWCYmsE3UwnTFCtTFnr 17 | IOi/Jt/7l83dDSP7nqD3nkintKDrLlTR9VbQ4BSSlfE1CckrkTuvBK0icu+1RJ9gp3Huwa/l7Hx9 18 | Gt/raEyDqxca2z4Ngobo0dggqHXft71Ja1eQQ+ud6qT2T6J0tdfymBc21varPh5PzcuBNQh6fPaQ 19 | Q/zZJkWl3mifLOew8/FE7d+Jfy7n7M86Vfe4xeOThxxqLG90iMB/YB10DrFKYs4XTVq4LNV4caAb 20 | GxWG6pOpx7PXG6P7kOxK19kInP23P1TQA9uQQ0pa1OptTNQKo45mu+0Zm54RNiczlrEFnxa8mEMO 21 | 6fKXs+nB7c0y4btWHcO/IeyCsEU2PecF42fsGfww/AYAAP//AwAComph4AQAAA== 22 | headers: 23 | CF-RAY: [3caa1b3a58405f93-LAS] 24 | Cache-Control: ['private, must-revalidate'] 25 | Connection: [keep-alive] 26 | Content-Encoding: [gzip] 27 | Content-Type: [application/json] 28 | Date: ['Sat, 09 Dec 2017 18:42:48 GMT'] 29 | ETag: [W/"d7c3bd0a78031a3d8db51815d8f565a3-gzip"] 30 | Server: [cloudflare-nginx] 31 | Set-Cookie: ['__cfduid=d39d46aab296c2e7960c6888a086680de1512844968; expires=Sun, 32 | 09-Dec-18 18:42:48 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 33 | 'XSRF-TOKEN=eyJpdiI6IkZoMFlDQmc3Tm45ZmxLQlNya2FZUWc9PSIsInZhbHVlIjoiajhLRzNwUDRPXC9TQ09hOEEwWTVHeSs4NnhXcGVGS0xIaTgrUlFBU2pPN0JaM2hzWjdwRklXcitEancrbTR1TittWkt5V2p6TUd4TlRtSDlRejNPdEF3PT0iLCJtYWMiOiI4ZmIzODIzNTI2ZDEyMGU0N2U1NGYxMGFhMTA3N2Y2MTgxYmM3Y2IyZWRhNjcyYTU0YWUwODlkMjljNWI3MGJkIn0%3D; 34 | expires=Sat, 09-Dec-2017 20:42:48 GMT; Max-Age=7200; path=/'] 35 | Vary: [Accept-Encoding] 36 | X-RateLimit-Limit: ['25'] 37 | X-RateLimit-Remaining: ['17'] 38 | X-RateLimit-Reset: ['1512845525'] 39 | status: {code: 200, message: OK} 40 | version: 1 41 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_edibles_get_effects_flavors.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/edibles/0000000000L6M7ENLJVX00000/effectsFlavors?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA0yOWwqDMBBF93K/RaSx2mYzMtWpDmgMMdGKuPeireLv4dzHgoo8QS/gYJveCUHj 15 | ESdJkiBC6Zi8jOJnaOSxUkptlNpOTH1FJnQvw8MAjecRJmvZi+eiJjHX1srNRdcH30AjPRreLhwz 16 | f22wUm5AHYDJ+WbeQ1mW5ZvSBweN2xmZmP3+4f4DVgxDm9C2Ech8hPeJ03c8Ck8DdLquXwAAAP// 17 | AwDupBs8CgEAAA== 18 | headers: 19 | CF-RAY: [3caa898f48f57850-LAX] 20 | Cache-Control: ['private, must-revalidate'] 21 | Connection: [keep-alive] 22 | Content-Encoding: [gzip] 23 | Content-Type: [application/json] 24 | Date: ['Sat, 09 Dec 2017 19:58:07 GMT'] 25 | ETag: [W/"272e96353d2fc5c74b77d6601c9cc9a3-gzip"] 26 | Server: [cloudflare-nginx] 27 | Set-Cookie: ['__cfduid=d15d4fee9e6dfaac0823ccced30b1ceb91512849487; expires=Sun, 28 | 09-Dec-18 19:58:07 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 29 | 'XSRF-TOKEN=eyJpdiI6ImJDMDJ3RVBHSGg2QlNhbUJHbERKUHc9PSIsInZhbHVlIjoiRlwvTlIzS2lPbThOZkgxZ1pTYldlaDVVdjh1eHp5c3dRVDM0VjNTZHNhbGo1Q0lRRVR4YVpvUU5PckYzcTVUWHRXVVIyZDlJRHF2dHYxUW5UalA1cmNBPT0iLCJtYWMiOiI0MTZiNDhmNDgxNTM2ZTRhYWQwZGE3ZWJlY2Q0ZTE0ZjI4ODRmNjZmMDFhOGU3Mjc3NmJiZTk0ODEyNzY1ZTNlIn0%3D; 30 | expires=Sat, 09-Dec-2017 21:58:07 GMT; Max-Age=7200; path=/'] 31 | Vary: [Accept-Encoding] 32 | X-RateLimit-Limit: ['25'] 33 | X-RateLimit-Remaining: ['11'] 34 | X-RateLimit-Reset: ['1512850045'] 35 | status: {code: 200, message: OK} 36 | version: 1 37 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_edibles_get_producer.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/edibles/4KXM32V9YFC3G2EUNWP400000/producer?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7yTsW7CMBCGXwXd7MR2SEDxVqGqQ9d2s1SZ8wEuIQmOQ6qivHsVCrRDWyFV4M2+ 15 | +79PZ8t7sCYYUHsozYZAwWPbrELVlcCgxRpBgTiv2fghuf/aAoPClWtQsAqhbpTmmnddF6MpSzN3 16 | jae68qGJsdpobmqn+U7GQvPaV7ZF8o3mf7G3/jLyCRcdTzVfH2fQfOsjrCwNw/jivzhg4DZmSZdx 17 | Dq3NgbdwBWmOmi/aonjBBNNJNpEkyRJOJBmxWFgyQmKeZiI3c5uhkCJ+rZfAwNPOUdcMT4RVWwZQ 18 | 4or3rvnJ1zOgt+ANhtu5z8JBbt28oO/uNL+u/CjsGXwGbjj4WdgzQE8mkL0Lg92aQMEdfmYiZBpJ 19 | GYnpSIzVOFciBwZD8b0qh4bnp9mQb2v7Wz6LZBKJZCSnKpEqmf6Q7/sPAAAA//8DAKRGPVUTBAAA 20 | headers: 21 | CF-RAY: [3caa5d5cc99522e8-LAX] 22 | Cache-Control: ['private, must-revalidate'] 23 | Connection: [keep-alive] 24 | Content-Encoding: [gzip] 25 | Content-Type: [application/json] 26 | Date: ['Sat, 09 Dec 2017 19:27:57 GMT'] 27 | ETag: [W/"50e6872a88cde1d64825a7004254d84b-gzip"] 28 | Server: [cloudflare-nginx] 29 | Set-Cookie: ['__cfduid=da35be3b5cbc07b7d3b8231b72d38dd281512847676; expires=Sun, 30 | 09-Dec-18 19:27:56 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 31 | 'XSRF-TOKEN=eyJpdiI6IkJPSW5Zd1E0NFNlYW92bnZwYllcL2hRPT0iLCJ2YWx1ZSI6ImNTWUFmNGtjNUI4Z092K1BieHBhaUc5bG9cLzR1WjRFV21OSlpwMm1TWVl6TnVsRGYxT1JhNlZuR3puOVlwNTl3QUR5ZW16VlwvWXVSUmtxbVdGVHJiOFE9PSIsIm1hYyI6ImI3NTU0YzUyMDZkY2Q4NWI3NjRiMDkxZmQwOTg4NmM2YTlmYWZkNWRmOGMyNDUzOTZkNTIxMWQ5YzhkM2YxMzcifQ%3D%3D; 32 | expires=Sat, 09-Dec-2017 21:27:57 GMT; Max-Age=7200; path=/'] 33 | Vary: [Accept-Encoding] 34 | X-RateLimit-Limit: ['25'] 35 | X-RateLimit-Remaining: ['22'] 36 | X-RateLimit-Reset: ['1512848483'] 37 | status: {code: 200, message: OK} 38 | version: 1 39 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_edibles_get_review.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/edibles/0000000000L6M7ENLJVX00000/reviews?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA6yW3XKbMBCFX8Wz1zhIQgjQXaev0F6FTGaRFltTDIwQdlyP370DjlNnpm0cu3cc 15 | obOHn49dDmAxIOjHAzSu/QEa1iH0gy7jMt7tdg8G2xYrN3jqOx+GB9Ntyhh7V8Zb/sDK2NPW0W4o 16 | 44o4FljnibFFppSRKkmtREys4FTlRiFleUYWIhh9c13OW3HBeFrGTJYxy66PKmOLWzcl0tivO+8Q 17 | NCiIwHjC4LYu7EFDDhH06NpnT42jGnQ7Nk0E2PcUXKDnFboWNHA2GbHZuHb1WgbbF0dTjZNj6J2Z 18 | CsopEH1Yn0Xtx99RQzf6s8P6/fOmG8P6vDBfGNkvAfRhejEU3IZAw3T/SyaXLFswpgXTCYcIppM/ 19 | u3ba8P3bVzhGMPb2Dv8xuhcCKdOsSo3MhZQsEVQrVWQqEzbhxpJhlLBMKpXcCYHg10eVcYWNJWq6 20 | l3cgXDzwVxJOKx+j8Oo8o/C6548snMQZhpN6o2Em6i4cBF+wVLNEJ/ImHP7tvx8HFBlVNq8QU0mm 21 | SupKoKgEr+vcsjRLZFEwKxS/FQdVxoyXscivjypjbLt2v+nG4X1fOH3fl41B3dQYZnkNDXM3+C+t 22 | QS0ZX4p8IZjmhZbqsyxc4b+fhZRLnhZGJihMIZK6ThVaayW3tckyrkSVWWHy5B4WpvlQXB9Vxlvy 23 | luq9p4HQm/V7IvIbJ4X8+6AAAb/nhLicE+ISBvEGw3z4SRbkkhULJjXL9AzjZ1n4yH98imBD00/D 24 | AXpcuRaD69pJhS5gA1pGYLqxDfNRT/65xxWB5iwCM3pPbTivRCfLLIdZT5ANoB+fjsfjLwAAAP// 25 | AwD/i0ZSnAgAAA== 26 | headers: 27 | CF-RAY: [3caa89920c127c22-LAX] 28 | Cache-Control: ['private, must-revalidate'] 29 | Connection: [keep-alive] 30 | Content-Encoding: [gzip] 31 | Content-Type: [application/json] 32 | Date: ['Sat, 09 Dec 2017 19:58:07 GMT'] 33 | ETag: [W/"75e631dfaf74c110308c33e58299068b-gzip"] 34 | Server: [cloudflare-nginx] 35 | Set-Cookie: ['__cfduid=d240135f81d21976161d0926bb462c4581512849487; expires=Sun, 36 | 09-Dec-18 19:58:07 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 37 | 'XSRF-TOKEN=eyJpdiI6IitDTkh4N0NCQVRtUnZkN2JISGxRT3c9PSIsInZhbHVlIjoiRlA3SUdEcmFUZ0kwdUhDeXN5SDZTWnVORGlOVGxEY0FLTkhUSnRkd1wvNWd5RGZvb09pYlJKMDVyMnZKNGZzcjhZeVFOZldcL3UrVVNvRHFzdzFtY0p6Zz09IiwibWFjIjoiMzRiY2VlNGY3ODg3NTkwODVkY2NmZTljZDRjMGI4OWUxZTU1OGRmODkyZTdlYmM2ZmQyYjdlNDU1NWE2ZTU4OSJ9; 38 | expires=Sat, 09-Dec-2017 21:58:07 GMT; Max-Age=7200; path=/'] 39 | Vary: [Accept-Encoding] 40 | X-RateLimit-Limit: ['25'] 41 | X-RateLimit-Remaining: ['10'] 42 | X-RateLimit-Reset: ['1512850045'] 43 | status: {code: 200, message: OK} 44 | version: 1 45 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_edibles_get_strain.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/edibles/4KXM32V9YFC3G2EUNWP400000/strain?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7xSXWvbMBT9K+Y+25Flp06tN5OSPJSxQNeuK4IhS3Ki1ZFcSU7oQv77kLOWLLSj 15 | DDI9Svd83aMdCOYZkB1otpZAYK5sG91w0/toasyjkg5i6HnHgcD4+v5Tnt2V32bpnwdiaJV+BAIr 16 | 7ztHKKJou92OONOa1cpZ2Rnr3YibNUWsUxRt8CilyHnLlHYU/Y35yX6M90CW/L6jiA/2k4atVftM 17 | 0VLZNnEhWHJ4cRQ92YQbIUduswwpbXsmJYhBrdlSfox+GHVH26kpavq2/V7XWTGpM3xZprmQomBN 18 | k4oxb7DkhSwxllmW4onMRz+6kMdJKaZm3TH9fFTwodVoNpg96TZ94/xzt1KKhA/yw67fF9jHsJRa 19 | esXdi08HBGY4oii66m3NdLQwyhkdLj7Po+verU6c54v5w9cT4jBd3t/dTuZXWbX4b1+Wotc0+0FE 20 | Ds3voGqWK6aV80wDgWoGMdyY3q+iqrGKMyDwUAUIX6lWWKkDhpteeyC4nJzR76vgPgYrN0pu3bH2 21 | xRmlX+RCbCuZl6LyQVswL70aPmyW4nGSXiS4iHBBxhnJLyGG8PjT6DBw+2Ua8H0n3sMXSZonaR5l 22 | OcHl2/j9/hcAAAD//wMAqEM+FQsFAAA= 23 | headers: 24 | CF-RAY: [3caa5d605e8320d2-LAX] 25 | Cache-Control: ['private, must-revalidate'] 26 | Connection: [keep-alive] 27 | Content-Encoding: [gzip] 28 | Content-Type: [application/json] 29 | Date: ['Sat, 09 Dec 2017 19:27:57 GMT'] 30 | ETag: [W/"9174e03897f52c3c490c5a116b40c1ad-gzip"] 31 | Server: [cloudflare-nginx] 32 | Set-Cookie: ['__cfduid=dac5420e8d06808c9f2c6c28e45f77bc41512847677; expires=Sun, 33 | 09-Dec-18 19:27:57 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 34 | 'XSRF-TOKEN=eyJpdiI6Ikhvek53SjErZmt3ODBvVThLOTg2OGc9PSIsInZhbHVlIjoibDMrajdoUGxVRUxUTjhkZ0dHSnNscUg5TkFzVnJrNmZOdnJBUkwxTDUramRIekwzdytUN2N0bWx0YkdJUnR3OHE3ZVE1K1ZVdDdKRTE4XC9uXC93TjJkZz09IiwibWFjIjoiZGNkZmQ2NGFhMWM0NjViMjljZmNhNTUxMmQzMTNmY2M4OGVkYzQyMjk5NmIzYzc5NDY5OTgwMDI3NjExMWEwOCJ9; 35 | expires=Sat, 09-Dec-2017 21:27:57 GMT; Max-Age=7200; path=/'] 36 | Vary: [Accept-Encoding] 37 | X-RateLimit-Limit: ['25'] 38 | X-RateLimit-Remaining: ['21'] 39 | X-RateLimit-Reset: ['1512848483'] 40 | status: {code: 200, message: OK} 41 | version: 1 42 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_edibles_get_user.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/edibles/4KXM32V9YFC3G2EUNWP400000/user?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA4yPvW7EIBCEX8XaJo0xYCKfQndKypS5joaYjYMOYwRLLOXkd4981+VHSjkjzTcz 15 | F3CWLOgLRD+eo50RNJwi2Rld87TLFoKPZ9DwTpSKNtzwdV270cZoX33JmJZMpRuX2XCbvOEfshOG 16 | 14K5GF5vKOZuKLJT8HHveEa6K82E1Kzos+ughZrD/2pSXt58wB/0EuoEGr65Y0ZL6I60v3SWkPz1 17 | ZS/kPZM9E4emV1oJrQ77Qj/j53KdeHp5hK2Fmtxf+YGJgSnRyEGrB93LX/Lb9gUAAP//AwCmoeFa 18 | YwEAAA== 19 | headers: 20 | CF-RAY: [3caa2ebbfa265f57-LAS] 21 | Cache-Control: ['private, must-revalidate'] 22 | Connection: [keep-alive] 23 | Content-Encoding: [gzip] 24 | Content-Type: [application/json] 25 | Date: ['Sat, 09 Dec 2017 18:56:07 GMT'] 26 | ETag: [W/"e203737e2ad6a8c846bd70fa453e9a73-gzip"] 27 | Server: [cloudflare-nginx] 28 | Set-Cookie: ['__cfduid=dedbf036d0465eeca374c521ef42128471512845767; expires=Sun, 29 | 09-Dec-18 18:56:07 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 30 | 'XSRF-TOKEN=eyJpdiI6Ik1BWGdtNDhYT281MitvTEd0VGNwT1E9PSIsInZhbHVlIjoiVzFnM0ZGR29RKzVpQjBUbjFBblRYWDkyc21YZnJTXC9VSmdVOUFYRVFOSWlFWTlrK0lFNnZVUmhWVkVoNG14M2xJa0lQOTI4SFF2RjdhYUpCOWNcL1diQT09IiwibWFjIjoiNDU2NjQ2YTVlMTUwNDFlYWRmNTcxYjAzNTIyNDc2ZWJhNWM5Y2IxZjQ5YjA1NGM1ZGM0MTg1MzM0MGM2NmEyMSJ9; 31 | expires=Sat, 09-Dec-2017 20:56:07 GMT; Max-Age=7200; path=/'] 32 | Vary: [Accept-Encoding] 33 | X-RateLimit-Limit: ['25'] 34 | X-RateLimit-Remaining: ['20'] 35 | X-RateLimit-Reset: ['1512846486'] 36 | status: {code: 200, message: OK} 37 | version: 1 38 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_edibles_list.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/edibles?sort=createdAt&page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA+yabW/bNhDHv4rAF3slRRJJPQLFsBlrszbN2sVZt1ZFQZGUxVmWVIlOmgX+7oPs 15 | WLY3qwkc0XmA/Y6S+D/e6e4H6uhrwIgkIPx0DXIy4SAEZzmhY+2t+AZ0MKUlBSGw2p/rucEJeu+d 16 | uPMh0EEm8jEIQSplWYeRGZmXl5dHlOQ5iUVd8bKoZH1Ei0lkklJE5oV9ZEUmZyLOeB2Z31P+Wt1N 17 | dyFm3FyLzK+VQQvGI1Om3IjJ1ZhXV5FZN24Zk7lbMamaJ3aTv5n8Hflple0m3akoJmR0x+XOH63X 18 | QxyZyTTLvljUhsSNExs7luujgDPoYAe5tpUQl3sJs13fThg9+rscAR2UVcGmlFcgbDNjmHLt58Xy 19 | OnNjNdw1N5aG/58da9ozHcirslnUPExAB7WsiMhB+OmzDjISD3ktQZiQrOY6kGmzUteaNI7RmLU3 20 | lmtpL6SkTn8TWTuu+IXgl3UTBFpMcwlCS1nKR+bS2kwHtOJEcvaTbEwzIrkU83cALRsbVmDAQLO9 21 | 0HZDBwMdNDf/KfLmgfPhoJk/LVnXfLeZb/nNfGSF2Nsyf6a3L32QFrTIiOTaIBWlNkiLYiy4Zmi/ 22 | 5kxQ0pkIr73Xg49KILGh3C8k6NJZg6aiNOjCWUMsXVUAjttM9gOT26z0AhjbxyhGBEJk04AQl1HX 23 | x0lswcCJfegEkCQxs/ATA0xMxpxpo6JgT5gyq5rZgTIQhii4H2UcZxfKdCbBOXp7eqwELhvK+4DL 24 | PqmiGCcHjjx7jqzK42E4gv0ddytnRIqL7t3Khw/Hw5dKgLKhvJfdSr10dX+7ldak0t1Ka+VAmedN 25 | mVXNPKXdimZox1dxJVhnNrw7GaBzJZTZUN4LZdKlq/ujTGtSKWVaKwfKPG/KrGrmcVLmDz4iubbG 26 | GjLu/iJ6+fGX92q+iDaU+0XLReOhsVaHCw8VEKXDUj8g6RC/Dz/IDT+I77iQcRe7AaSYJb7jE0yR 27 | RZhHObVcaPvcg8w58GP//FgVxi78wKGD1H4LnU1HpNIGd+zXIvzmd0/Noc66cs+HOo2LBlXfpd1u 28 | qKeDnq3a96GHc0MPJwkCzCyLOhgGPmGuE3OPeB7k2LIpwjCxGUpQfKDHA5z7tFWxCz2cECG1u4// 29 | 0OOW/smb0+A0UEKPDWWF9FDZNdluSAE9eumQHOjx+OmxqoonQY9b+iLwz1d/DZXQY0NZIT1UdkO2 30 | G1JAj146Hwd6PH56rKri8dOj89W/ehccq+l4bCirg4Z6WijBxIEPz54PqwJ4GD5s72x81sGEN/9V 31 | vQYlGYmcSFHkzUgWkmQg9Fzk6MuQ2JYOSl59KeeZ2ozotKp4LpdX9MW0+bBuJuNFEOdxzfk3uWs0 32 | f6yLSr5oY/VDY+AFBLPZbPYvAAAA//8DAL1Stj1tKwAA 33 | headers: 34 | CF-RAY: [3caa41401f735f93-LAS] 35 | Cache-Control: ['private, must-revalidate'] 36 | Connection: [keep-alive] 37 | Content-Encoding: [gzip] 38 | Content-Type: [application/json] 39 | Date: ['Sat, 09 Dec 2017 19:08:45 GMT'] 40 | ETag: [W/"196227dd02ce0f0f190e9235fcb2a5c4-gzip"] 41 | Server: [cloudflare-nginx] 42 | Set-Cookie: ['__cfduid=d4d80c47c1dadda793b160625bdce014e1512846525; expires=Sun, 43 | 09-Dec-18 19:08:45 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 44 | 'XSRF-TOKEN=eyJpdiI6Ikt0OWo0WDhFSHlhWFg5TmplRDRtc0E9PSIsInZhbHVlIjoiXC9lYTJva2xYYkdFTjlEOW5KTUplSTczYkY4aWNrSHBUYjZqd1ZFWFViMk5vUlZzMWFsUmRpSThwRzgwejF4cDZJazhZd05hNk1BQkVcL3lMXC8zQVcySFE9PSIsIm1hYyI6Ijc0NjIwMmM1MjgyMTQyZWJkNmUyM2U0MzA1MzhkMDcyOWVjMDI0NDAxOTkxZDEwYWVmOTZmYmEyZGFiMzRiMGMifQ%3D%3D; 45 | expires=Sat, 09-Dec-2017 21:08:45 GMT; Max-Age=7200; path=/'] 46 | Vary: [Accept-Encoding] 47 | X-RateLimit-Limit: ['25'] 48 | X-RateLimit-Remaining: ['24'] 49 | X-RateLimit-Reset: ['1512847425'] 50 | status: {code: 200, message: OK} 51 | - request: 52 | body: null 53 | headers: 54 | Accept: ['*/*'] 55 | Accept-Encoding: ['gzip, deflate'] 56 | Connection: [keep-alive] 57 | Cookie: [__cfduid=d4d80c47c1dadda793b160625bdce014e1512846525; XSRF-TOKEN=eyJpdiI6Ikt0OWo0WDhFSHlhWFg5TmplRDRtc0E9PSIsInZhbHVlIjoiXC9lYTJva2xYYkdFTjlEOW5KTUplSTczYkY4aWNrSHBUYjZqd1ZFWFViMk5vUlZzMWFsUmRpSThwRzgwejF4cDZJazhZd05hNk1BQkVcL3lMXC8zQVcySFE9PSIsIm1hYyI6Ijc0NjIwMmM1MjgyMTQyZWJkNmUyM2U0MzA1MzhkMDcyOWVjMDI0NDAxOTkxZDEwYWVmOTZmYmEyZGFiMzRiMGMifQ%3D%3D] 58 | User-Agent: [python-requests/2.18.4] 59 | method: GET 60 | uri: https://www.cannabisreports.com/api/v1.0/edibles?sort=createdAt&page=2 61 | response: 62 | body: 63 | string: !!binary | 64 | H4sIAAAAAAAAA+yaa2/bNhSG/4rBD8MGSDElUhcKKIbEG3ZpvGVtGrSpi4I32ZptSaHoZF7g/z7I 65 | F9lOo9VwRDcJ4m+UxPfwpXgeH1G6BYJqCqKPtyClYwki0BlkPBtRLVsdlRT5tPX2akKVBBaY8JyD 66 | CMDq5wc+OSVn6H133gQWGCXpEERgoHVeRL12r31zc3PEaZpSlhRK5pnSxRHPxr02zZNe+9o5gr22 67 | FAkbyaLX/j/lK7Wb7kLMXh7rta+UzTMhe209kDaj06FU016br0zafG7SLlYmGVXl9fsFW3beOdhE 68 | jfYLtKN+Mqb9Ha3MLy02bobba8eT0eizC4WDvED6DpICEyeMOWKxB30PQ4jc0BU8Djh3jv7O+8AC 69 | ucrEhEsFompFnQ9k62Qx2NpVtG7uu4pWgb9cRxvaMwvoaV4OSitJNbBAoRVNUhB9/GSBEWXnstAg 70 | iumokBbQg3KkPhyXxjgT1YnVWKoDA1oM/kxGVVvJ60TeFOUk8GySahBBY8nRa6+izSzAS1tSHOsy 71 | tKBa6mR+D1zoYBsS2yUtJ4gwjLAPLFCe/DdLywvenXfK/pNc1PX3y/4wLPsjGOHwnv4zq7rpvyia 72 | ZiPaOqGq9f2F7NP0h9qb/9Mflz9fGEHIlnKzCOkvDNqMKvu69GcGHveFaQYb9yk3AgyKhO+GDEqJ 73 | qXQlZmEQco4ljjnEoaAwDkOfsicGjCKlfPiEgbFOhX2AgSLomQXGCU1pSlvr8qM7ieMkbdmtt1Qn 74 | 17R2JVx2Lz4cG6HHlnKz9GBzt/b6r3s8d2sXK68GUPLVmM1w5athHgIZsoQMgcQXDsbCDQmikJCY 75 | u4ITj7GAs1BCIZjneTh+YpBhdChFq59lYifSkEdJmnXa7EMaL3IfWJp43r6k+XXKVCJql0PX/evS 76 | TJ2ypXwY0gxWXg9ImiqmWdJUYV5I87xJs06bJ0Wa+r0UfOx2zOylbCofBDAHJYtppLyw5NmzZJ0h 77 | 34Yl+z8f/ZaKhNc/H5EOOn1vBiqbyoepWpKV1wNWLVVMs1VLFeaFNI+LNI6xtHmcVUuXTmm6AZpO 78 | lg2T+hdAH7pdFBjhy5Zys3wZlx43cpCvPBrgSm2sZnhSK/8QjsRLjsRB7Do8iEkYBEGAA4moH4SO 79 | kJBI10FuIJgTohC+cOTwFcs6PfbhiB8hbLZiOZuM82GStjp0WE8P9O4M/26EHlvKzdIjXziz+cKZ 80 | AWbcidAMKe6IPoQP4ZIPoWAhZ55ETIaMxwgLSaTrMx97PvSZ48GAIU7w8+aD4z5KQKwzYB9ABBEK 81 | DQMiy3mmdth4fdM9fW1m43VLuWFILNwZ3Wj9IkZDoLgr+xBU4CUqMKSCCocQiTh3eIBhzIXPOYQu 82 | dVzikFAGmNCn9iHJ7u+FHykl1imwDyVI5HhmH0eWlKj/euTNadfQ1yObykbgYJQKTePghQPPmgPr 83 | 1f5tOHB/tfDJAmNZfqF6C3LaT1KqkywtWzrTdASiwEeeVe3UQAvkUn3O56u0bPGJUjLVyyOuteg2 84 | bxZlZ7yYxPm85qXrbFLsO6M/FpnSr6r5+q4M8soBFkjlP7pRUQRms9nsPwAAAP//AwBXWOepvCsA 85 | AA== 86 | headers: 87 | CF-RAY: [3caa41423fd85f93-LAS] 88 | Cache-Control: ['private, must-revalidate'] 89 | Connection: [keep-alive] 90 | Content-Encoding: [gzip] 91 | Content-Type: [application/json] 92 | Date: ['Sat, 09 Dec 2017 19:08:46 GMT'] 93 | ETag: [W/"f47a385fb1b1447f30302e06ffc25deb-gzip"] 94 | Server: [cloudflare-nginx] 95 | Set-Cookie: ['XSRF-TOKEN=eyJpdiI6InpTWDRQZTZNU3RxeGt3WkU5UWpwNUE9PSIsInZhbHVlIjoiR0tJTld6ZkhnSGR0ZnFpcmduQzdkRzJ0V3BVeFltS1J4eHBqRWpTT1wvd3lmTEZ0MWpZS2FJSHNGaDM4b0J2dlNzSWZ0cURCNHVxaTZxbWhWdHd4VXF3PT0iLCJtYWMiOiIzYmY4ZDczNTc5Y2MzNTA2YmRmODg4YzMxYWYxNDg1NzRmZmE4ZjlmMzRiNDY5MWUyNTQzZmEyYjU0NTU4ZjZmIn0%3D; 96 | expires=Sat, 09-Dec-2017 21:08:46 GMT; Max-Age=7200; path=/'] 97 | Vary: [Accept-Encoding] 98 | X-RateLimit-Limit: ['25'] 99 | X-RateLimit-Remaining: ['23'] 100 | X-RateLimit-Reset: ['1512847425'] 101 | status: {code: 200, message: OK} 102 | version: 1 103 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_extracts_get.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/extracts/QLG39RN2AFPMR6WLTPLW00000?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7RTX0/bMBD/KtE927FTGB1+Y5MATd3GUBEvlpDjeNSQ2sa+kDGU744S2sAkOqFM 15 | uyf77Pv9se8eoVKoQDyCU2sDAj7VSt+2Ck3Mvp9kNDv1zjxovy6BQKODBgE/Fid7h+ffZkfHZ1/P 16 | Dy4Xy7PFJe8DCNTW3YKAFWJIQjLJ2rbNtXJOlTZFE3zElGu/lkwFK9l9kXPJzC+MSmOS7G/Qd/F9 17 | wBs0uklKdhep9pWR7MYZtDpJhitDtaot1d45o9F6J1k5OpdstXWdB3cNBEoVe4iJAjbV/yKgifVE 18 | 8gmcQMCu1fU77Q5Xk2QJo7IuSeb81ZDLb0IvPURfNdrEV0325VnTS0vxMYZ/f9lObaktaZJsN3ZH 19 | AB/CYPOV9Wcfu0birTHgf8ZUzeMD7kbuCNSqXJqEIH6qOhkCuNLjWpfVuI7m3po29T60bxyC4P9v 20 | PCXb0nUEdDQKTXWEPXel0KAd3nHGiw+U71M+z/hcFHMxmwGB/vC3d/2Fi+Xnvr4J1a76A8oPKf+Y 21 | FXOxx0Wx/0Z91z0BAAD//wMAP3xPgdQEAAA= 22 | headers: 23 | CF-RAY: [3caa996e08687930-LAX] 24 | Cache-Control: ['private, must-revalidate'] 25 | Connection: [keep-alive] 26 | Content-Encoding: [gzip] 27 | Content-Type: [application/json] 28 | Date: ['Sat, 09 Dec 2017 20:08:57 GMT'] 29 | ETag: [W/"f91a70f5354fd55aa6a5d2bb84ec8d8e-gzip"] 30 | Server: [cloudflare-nginx] 31 | Set-Cookie: ['__cfduid=db067659be6a341baecb3a1d7c9a7164a1512850137; expires=Sun, 32 | 09-Dec-18 20:08:57 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 33 | 'XSRF-TOKEN=eyJpdiI6IjJSOGxKcVVcL1Z1dEhCcWVPdDgwZDRBPT0iLCJ2YWx1ZSI6IlhIUTVJM2xBczdXMmExSGZzaDhteTNqaTdtT3NTNHlzYXlTZ1RFRFVmbE5NYit0OUE3Z1IwVCtxeVJNODZcL2oyS1JHT09xMHhIQ1B4eEQxSlwvTUcxV3c9PSIsIm1hYyI6IjZkMGQ3OTkzMGIzNjMzYjRjODZkZDUxY2NiMGJhNzdmMGI3ZWVhYTY5ODIwNTE1NWQyMzhlYjI4NGE3ZmRhNWEifQ%3D%3D; 34 | expires=Sat, 09-Dec-2017 22:08:57 GMT; Max-Age=7200; path=/'] 35 | Vary: [Accept-Encoding] 36 | X-RateLimit-Limit: ['25'] 37 | X-RateLimit-Remaining: ['24'] 38 | X-RateLimit-Reset: ['1512851037'] 39 | status: {code: 200, message: OK} 40 | version: 1 41 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_extracts_get_available.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/extracts/9XVU7ZCENQVU7TGRFHPC00000/availability/geo/37.7749295/-122.4194155/10?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA+SZa2/bNhSG/4rATxtgWrzqQmAYMrfJgLVdVjfBsGkIGJmWicqSRtJO3MD/faDt 15 | OLFgFIk3bcmsTyLNw5eXB+ci34GRdBKI3+9AJacKCDCYKGMWwblWwTeb959mdvJtAINL2dRGf1Em 16 | GEjjjB4VCvTALG9yIED66+VF/Nvg7YdfLi/iT2cfT388HyD/gB4odfUZCDBxrrEiC7Pw5uamn8uq 17 | ktfaGtXUxtl+Xk+zUDY6C+e4j7JQ3Tojc2ez8GtTu0XjV70Z7LXqXDpdV0BstzQ8Pf357OzQdYy0 18 | bVRlpdHKZmEus9DKCo6NrHJt8zoL7XhcF4WfXjogAI37cYxjirHvqgogAMSE9BmOOEMpWPZAY3Su 19 | gKhmZblpXE1kOb4qjJz6GXh/tbf1L5tO9LhP6WLiJrsz/DmTximzZ9p6VrXldrpyo6RToxPnz2wk 20 | nXJ6dW4EYQYRhwQFBAuSChr7E9dT9aWu/ICLTwO/nVkz+ro9DhATnArE99gve/9r9s5PPg66Q6+R 21 | Jt8lL0rSNGmTxwhmTyGPvDDycOrJ4/hQ8jb2TKzv66jIe1fPVTCcyPxzMKjrRhnp9Fx1hmJZzxW0 22 | Xg7mu3JbNqME04S12CQsilP8FK+IXpxXxImgWDD0d7xiJAg9OjZ/kOZamkUwqKV1nSF5vVaB+b3K 23 | lsQEp5TTFokojlOKX218ZlTg5AASY0hxgJBAWKxSliMj8WR40iGAVraiM4oT3uKOJhwz9ho9IA4Q 24 | EYgKyp7LXQQRhRgFBHkPyKKj4+58ZppSBUMnTfD+TWcENisZaJ00cDraYZFHEWWknSmmiJL4KSyS 25 | l+cDic8USfpcFjlEKSQsQInAkSDHx+J7NdJnRqkqeHvbGGVtZzhO1UgXXgmqB6WH/BAnpE0kTROe 26 | xK8sP+SbqOrzw1RgdACR9/aMCJocHZFnRlo7qZtGmWB42hmOxYMMtON/kMV9dfTjsf8yiSvfSJHA 27 | 5DAS1/bsOCuVhV+xCt6oUs+VWXSYLC5gLo2Co0dKj6I1ZrT9XYcSHiXkCTyyfb4x5v9RuMYY4tin 28 | jpQLwp9fsmztGRLs+JBch+p3So47j9frWF0qOd4XsBPE0ySJ22V0mmLOXt3Hxhhi6stoFAvCDnCT 29 | DKIoIFRgJPDeFPKPHpgq/1/LHWhkoavttbrayRIIzHsgr2eVAwKjHmiUuWpkodatfGaMqtx9T29t 30 | tGpaIMj6/u0KEnXruoAzC+Vc6lJe61K7RRYWqs7CVU3LUpLyLLwvIBjmPAsx+t4v7jsClsvl8i8A 31 | AAD//wMAIzTYbWcaAAA= 32 | headers: 33 | CF-RAY: [3caa9d2619689883-LAX] 34 | Cache-Control: ['private, must-revalidate'] 35 | Connection: [keep-alive] 36 | Content-Encoding: [gzip] 37 | Content-Type: [application/json] 38 | Date: ['Sat, 09 Dec 2017 20:11:29 GMT'] 39 | ETag: [W/"ddd200c49d95cabcf239daa5d6700986-gzip"] 40 | Server: [cloudflare-nginx] 41 | Set-Cookie: ['__cfduid=d14ab6869fa42572a00edb87a0f46c94d1512850289; expires=Sun, 42 | 09-Dec-18 20:11:29 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 43 | 'XSRF-TOKEN=eyJpdiI6InIwYmZmQnp1SWtCREpwXC9zWHpVTTdRPT0iLCJ2YWx1ZSI6IjJWUFhHKzdwazNsUGt4UTYySkdIYzhlUXNaOUZaMnVDeml1a2RkUEczakZqdG9PRkE1cENTWjRVOXhiQjRGWE1odWdWeG9BXC9KdFFobkNROE1Gc0h3Zz09IiwibWFjIjoiZWJkYjQxNzFiYjlkYzZmNjNlN2MzZjA4MzUxYzRiNTlkOWE0MmJiMDU4ODVjYTg5ZjFkMWEyZDhmODQyN2JiNSJ9; 44 | expires=Sat, 09-Dec-2017 22:11:29 GMT; Max-Age=7200; path=/'] 45 | Vary: [Accept-Encoding] 46 | X-RateLimit-Limit: ['25'] 47 | X-RateLimit-Remaining: ['13'] 48 | X-RateLimit-Reset: ['1512851037'] 49 | status: {code: 200, message: OK} 50 | - request: 51 | body: null 52 | headers: 53 | Accept: ['*/*'] 54 | Accept-Encoding: ['gzip, deflate'] 55 | Connection: [keep-alive] 56 | Cookie: [__cfduid=d14ab6869fa42572a00edb87a0f46c94d1512850289; XSRF-TOKEN=eyJpdiI6InIwYmZmQnp1SWtCREpwXC9zWHpVTTdRPT0iLCJ2YWx1ZSI6IjJWUFhHKzdwazNsUGt4UTYySkdIYzhlUXNaOUZaMnVDeml1a2RkUEczakZqdG9PRkE1cENTWjRVOXhiQjRGWE1odWdWeG9BXC9KdFFobkNROE1Gc0h3Zz09IiwibWFjIjoiZWJkYjQxNzFiYjlkYzZmNjNlN2MzZjA4MzUxYzRiNTlkOWE0MmJiMDU4ODVjYTg5ZjFkMWEyZDhmODQyN2JiNSJ9] 57 | User-Agent: [python-requests/2.18.4] 58 | method: GET 59 | uri: https://www.cannabisreports.com/api/v1.0/extracts/9XVU7ZCENQVU7TGRFHPC00000/availability/geo/37.7749295/-122.4194155/10?page=2 60 | response: 61 | body: 62 | string: !!binary | 63 | H4sIAAAAAAAAA+SXbWvkNhDHv4rQqzuw1npcrwWlXDdtCkfa9EjC0foIijzxitiyK8tJN2G/++HN 64 | ZvNAGq4hB3eNX0kjzfw10o+RfIVLEw3Wf11hbxrAGs8XEMIS7TtAbzbt90O/eIsIOjJdG9wlBDQ3 65 | IQZXVoATPNjOYo3zj0eH2Z/zn3/74+gwO9j98Muv+3M6fjjBtfNnWONFjF2vi7RILy4uJtZ4b05c 66 | H6BrQ+wntm2K1HSuSM/ZhBYp/BODsbEv0qdCx2U3rnozedRqrYmu9VhvUzpYANoNAB7NQ9v3z11Q 67 | 6foOfG+Cg75IrSnS3nhyGoy3rrdtkcYFkGrUIfZGx0SsscgmGc+zGctGk6+wxoRxPpGCTkWm8CrB 68 | XXAWsPZDXW86xwtTnx5XwTRjBD5ZZ3s9sjHSuzZw1SIu7kf4ezAhQngkbDv4h3L3TDaAiVC+i+Mu 69 | liZCdOud5JRJQhXhDFGmFddqTGkcvGz9OOHwYD6mM3Tlv/krwjjhOeJUK6nF9BH/VfJ/pnHPBVMB 70 | 2oPSWedN/dVwbNZCpLkrtOWRzZjIZw94nE2FzPkX8CjpN8OjIjQjgiE202qmhfzvPG78c02pptmr 71 | 4/GnuhgoPbUN+t2c1caXLwdkex2wSE/qoSHtbfgbDGeMS8keYMgzmrMvoZCrb68qSi2o5uoZFEpC 72 | c8SF5lIz9uoo3IE6GsQY2oHanUNYvhyFjQnOE+viskjLUYYwRso7MlsaM0Fn6j6MikkqlPju7uiM 73 | MIE401JoOn0GjVPCJaJUs1xL8fpqIoQzqGGJ9k104GOPdkM7dC/H5MlG4LZFuo0UqW6ktlxOBc94 74 | /qBK5nTKqPi+LuttmeRa5I9ftk+CecdfKs0eBfNTghsY/2mucGcq57dnG9toaqyZSrBtBx+xVgnu 75 | IBx3pgKsGU2wHUIAHzcWnlz7rLv9uj8ef78OHeDctUP/NSAtUnNuXG1OXL0uWhW0RTo+2jKZ81wV 76 | 6fVrjeWSKVWkjP44LvAHhler1eozAAAA//8DAEanYafSDQAA 77 | headers: 78 | CF-RAY: [3caa9d2919ef9883-LAX] 79 | Cache-Control: ['private, must-revalidate'] 80 | Connection: [keep-alive] 81 | Content-Encoding: [gzip] 82 | Content-Type: [application/json] 83 | Date: ['Sat, 09 Dec 2017 20:11:30 GMT'] 84 | ETag: [W/"b6e46d1391b878506ed81649a4ae7b2a-gzip"] 85 | Server: [cloudflare-nginx] 86 | Set-Cookie: ['XSRF-TOKEN=eyJpdiI6IlVKcGhHUlo2TUZBdzQ3elhMRTErQ0E9PSIsInZhbHVlIjoiK2RmcTQ4SENkT1FRZWVJT3FZM09PTkdrSHFneDZ3MVNCRXI3ZkkrbkxVUUFkaDljUWNEeVdNc0hjemZJVEFUUU1uRjBOUWlKcFhPbXpqcmd4ZGpiT1E9PSIsIm1hYyI6IjIyM2E2ODVhNjkxZTExNmQ0MGI3YWU3NTc2MTY4ZmM2NTk4MmQ0MjA2N2E5ZTdjOWIwZmYxYjY0Mzg0Zjg0MjAifQ%3D%3D; 87 | expires=Sat, 09-Dec-2017 22:11:30 GMT; Max-Age=7200; path=/'] 88 | Vary: [Accept-Encoding] 89 | X-RateLimit-Limit: ['25'] 90 | X-RateLimit-Remaining: ['12'] 91 | X-RateLimit-Reset: ['1512851037'] 92 | status: {code: 200, message: OK} 93 | version: 1 94 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_extracts_get_effects_flavors.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/extracts/9XVU762EQ4VU7TG3N9NM00000/effectsFlavors?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA0yP2wqDMBBE/2WepaRCS5ufka1udUFjSDZeEP+9VIj4tpyBObMbGlKC3cDJd2MQ 15 | gsXrZowxKFAHJpVJdIXF+6TUD+JaWDwzcmn4OI4RFo/MyHtWUa5aEncNmrBWw5i0uzZ8Qzo0LvV9 16 | geil/jvLHDMF7dbrtjimAIu7OcHMrLnAi+N8k1uEjxdOW+BJeI6w5b7/AAAA//8DAAoeb0QDAQAA 17 | headers: 18 | CF-RAY: [3caa9d2d0c00791e-LAX] 19 | Cache-Control: ['private, must-revalidate'] 20 | Connection: [keep-alive] 21 | Content-Encoding: [gzip] 22 | Content-Type: [application/json] 23 | Date: ['Sat, 09 Dec 2017 20:11:30 GMT'] 24 | ETag: [W/"5fb4b05a1ebd5365ab6b6288220d9ba5-gzip"] 25 | Server: [cloudflare-nginx] 26 | Set-Cookie: ['__cfduid=d7f630f1a0c9abab80466adfc5039c14d1512850290; expires=Sun, 27 | 09-Dec-18 20:11:30 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 28 | 'XSRF-TOKEN=eyJpdiI6IjRiSlJBQzNNc3lvVWlZUEFTTkFjdkE9PSIsInZhbHVlIjoiZGp4UGZ4XC9sTmZmdms3NjFxN3F0a3RWcDEwdlZ5anpZRGRqb1lkUTM4dW5TYzF6anFFcU5FY1wvTkdpa3p6YThPRXpTS09BeCtDeTlKS1VkWXNKMEJWZz09IiwibWFjIjoiYjVjY2E5ZTc1ODUxMDUxMGRhNjc3YjNlNzAzNDliMGY2YWZhNzk2MjFjZGJkOGVlYzFjNWRjNDhmZTE0MzFmMyJ9; 29 | expires=Sat, 09-Dec-2017 22:11:30 GMT; Max-Age=7200; path=/'] 30 | Vary: [Accept-Encoding] 31 | X-RateLimit-Limit: ['25'] 32 | X-RateLimit-Remaining: ['11'] 33 | X-RateLimit-Reset: ['1512851037'] 34 | status: {code: 200, message: OK} 35 | version: 1 36 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_extracts_get_producer.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/extracts/QLG39RN2AFPMR6WLTPLW00000/producer?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7yTXUvDMBSG/4qc67RJv9aaO/FOEEQUbwKSJqczs2u7NF3F0f8u2dz0QmUgW+6S 15 | c97n4SRkA1o6CXwDjVwicLhp0BnVA4FBdQo4sMO6u72fPX1tgUBtmlfg8OJc13NBBR3HMVSyaWRp 16 | eotda10fqnYpqOyMoOsoZIJ2ttWDQtsL+hd7ZY8j73HB56mgi90Igq5soFqNfhZb/5MGBMxSzvE4 17 | zLa13+IqU6OgsaDVUNfPcZ6xJE3KyzROWFHNYqlZnJcyyTFhWBWpLPQMkzxcdHMgYHFtcOz9+6h2 18 | aBxwdsJbF3Tvmwjgm7NSue/u5KTug9DLtSlrPN/ce99EYBdw53MfhBMBZVE61FfO27V06Mz2V8Ys 19 | ygKWBiy/YDlnOU8zIOCL723jGx4frn1+6PTv+SgOWOzzUcZZ8UN+mj4AAAD//wMAS4t2uw8EAAA= 20 | headers: 21 | CF-RAY: [3caa9a99c94e98fb-LAX] 22 | Cache-Control: ['private, must-revalidate'] 23 | Connection: [keep-alive] 24 | Content-Encoding: [gzip] 25 | Content-Type: [application/json] 26 | Date: ['Sat, 09 Dec 2017 20:09:45 GMT'] 27 | ETag: [W/"6ba4c664528b26411c4a0ee2e116d0bf-gzip"] 28 | Server: [cloudflare-nginx] 29 | Set-Cookie: ['__cfduid=d85175123b08d942f947959a3e18c50531512850185; expires=Sun, 30 | 09-Dec-18 20:09:45 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 31 | 'XSRF-TOKEN=eyJpdiI6InlSZGQ2SFdCR1wvSFF4cDFxZDdLQitRPT0iLCJ2YWx1ZSI6ImwyV1FqWmRvV05YcjR2M1IrTFwvN2JBMUoxQzhNNDA0NDVNMUZTbWRxdDlVVTZNOWNNaDNsYTgxdGtXd3hmUURpZ2lYWnJIenNOS0lHQk5leDVBalpHdz09IiwibWFjIjoiNzVhNDhjYTZjMTNlMmVkYTk1MTc0MWRjN2Q1NWFkNTRmYmMzODBhOGM0ZWM3OGJlYjFlZDIxNGJhMjFlYjdkZSJ9; 32 | expires=Sat, 09-Dec-2017 22:09:45 GMT; Max-Age=7200; path=/'] 33 | Vary: [Accept-Encoding] 34 | X-RateLimit-Limit: ['25'] 35 | X-RateLimit-Remaining: ['19'] 36 | X-RateLimit-Reset: ['1512851037'] 37 | status: {code: 200, message: OK} 38 | version: 1 39 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_extracts_get_review.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/extracts/9XVU762EQ4VU7TG3N9NM00000/reviews?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA6SUy67aMBCGXwXN2uBbEhLvqr5Cuzo5QsaZgNXEthwHShHvXiU0KqfqgiN2c/v/ 15 | sTSffIVGJw3q7QqddT9AwTGlMKia1vR8Pm+Mdk7v7RAx+JiGjfF9TXWwNT3xDatpxJPF81BTgRnf 16 | tpIXmrecM25K3Fd7XbSFNFVbVRlWmSy0AQJj7J7b89ec8bymLKspE8+vqmnjzdocbddZd0jeAQEc 17 | w9FHq0FBAQRMRJ3syaYLKCiBQNDW7SJ2FltQbuw6AjoETDbh7qCtW3S66607gIIMCGj30+JkcRcM 18 | wZrJT0z7dEzHyx9VG0f7MObHuMRNvOx6P6bjUpgfhs2XBOo6nQiT7XHyZDxfs2zNxEpIlZdK5EBg 19 | av7ybhr4/u0r3AiMoXlBfyOv4pALU2amzRvRbhuRG5417T43QnImq6psm6KQDCt8BYdtTYV8flVN 20 | tfPu0vtx+AgCZ/+SMFeeQCH7gEL5iMJ88IUE9kjCbL6gMLfuJNwbnyRhuxZyxSqVFYrLz5PAxVqy 21 | FZ/1efk/Et4J9Dj9EFcI+mCdTta7KUs+6Q6UIGD86NIcBYy7oA8IijMCZowRXVoq5C6Z02HOJ8QG 22 | UG/vt9vtNwAAAP//AwCWYpiaiQQAAA== 23 | headers: 24 | CF-RAY: [3caa9d2f8cdd9901-LAX] 25 | Cache-Control: ['private, must-revalidate'] 26 | Connection: [keep-alive] 27 | Content-Encoding: [gzip] 28 | Content-Type: [application/json] 29 | Date: ['Sat, 09 Dec 2017 20:11:31 GMT'] 30 | ETag: [W/"d2573091224550e994ca6f9c17cb962f-gzip"] 31 | Server: [cloudflare-nginx] 32 | Set-Cookie: ['__cfduid=db0099c195dbc32a8c8e2bee6514ebe751512850291; expires=Sun, 33 | 09-Dec-18 20:11:31 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 34 | 'XSRF-TOKEN=eyJpdiI6Im8wSlZ4alNWZVwvQTNXZ0hWM09MSDR3PT0iLCJ2YWx1ZSI6IjBZTm9HR1dJdjE2emp2ZVA4Mzk5WFhHbmJXQzFpWlBZY2E4SVd1UFwvdWJWWjhLdjRUM2lTdmt1eUh1SEQxcEE2UDRQYmZNXC9kZUhUZmVCVnYwUWxqckE9PSIsIm1hYyI6ImU5OWNjNGIzMjQ3ZTIzZTFhOTk1ZGY2NGU2ZGIxZDVkZWNjOWMxMTFkODcxNzBjNjJlMWIyMWU3ZGVlZjE1YjIifQ%3D%3D; 35 | expires=Sat, 09-Dec-2017 22:11:31 GMT; Max-Age=7200; path=/'] 36 | Vary: [Accept-Encoding] 37 | X-RateLimit-Limit: ['25'] 38 | X-RateLimit-Remaining: ['10'] 39 | X-RateLimit-Reset: ['1512851037'] 40 | status: {code: 200, message: OK} 41 | version: 1 42 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_extracts_get_strain.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/extracts/QLG39RN2AFPMR6WLTPLW00000/strain?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7ySXW/aMBSG/4p1rjYpwUlICPEdQ4ObdnRrod1kaTLOAbwGJ7UNtEP89ylZYaxC 15 | VTWJ+fJ8Pe/rc7aQCyeAbUGLJQKDD4WQ9xvh0JDREDxYyUoCg88Xw3b25VPUGwR/P/CgUPoeGCyc 16 | qyzjlNPNZtOSQmsxVdZgVRpnW7Jccioqxek6bAWcWmeE0pbT1yY/mLfN/T3Mf45x6hboS1EoX5Za 17 | o3Sq1JxOD844fTC+LHNs2fW89miKs3DAA7UUc3zb8KbUHv1MzOlsVRTf41QmMugmcbsdp2GaJnEm 18 | 41kusySZpnHUDVPstDui2/pR1W4sYt4vl5XQT0d7vVkg6YtCkf5B6ovtBifeP28XMfdlI0Lhfskn 19 | ATsP5qjRKWn3ai0wuESdl+RqZSpLHsm10GSARos6OBFFgU9kNCTvrgcTMhq+/2Mku5uM04u7q2z8 20 | gkMeSZP7+PXy2+1/O2FOD952DQSba9hCbzZfCK2sExoY9AZ1Wi5UkRvUdV6WK+2AZWdUdsDtPDC4 21 | VrixR+TwjOQ9rfZsUDjMe65G58KhU821RkEY+0HqR10SZizssCgED+rkz1LXBeObft2/qvJX+rt+ 22 | ENb9ScTi4ET/bvcLAAD//wMA1ddOwv8EAAA= 23 | headers: 24 | CF-RAY: [3caa9a9efd7876d0-LAX] 25 | Cache-Control: ['private, must-revalidate'] 26 | Connection: [keep-alive] 27 | Content-Encoding: [gzip] 28 | Content-Type: [application/json] 29 | Date: ['Sat, 09 Dec 2017 20:09:46 GMT'] 30 | ETag: [W/"f2b1775c890d1a7bcadd8188b0e3a5d1-gzip"] 31 | Server: [cloudflare-nginx] 32 | Set-Cookie: ['__cfduid=d3c71488507d68edc8c783265dcb323c71512850186; expires=Sun, 33 | 09-Dec-18 20:09:46 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 34 | 'XSRF-TOKEN=eyJpdiI6IjZcL0RLSVAwMktjZU5tTzdCcnpoRDNRPT0iLCJ2YWx1ZSI6IjhhcU1xZTdUQ2JQSE1YZUhFRWF5TWFVSXJ4OG8rMnFjV1JrRlNmVklPXC9DNzI2MEd3UjZJRGNTY09tRmZaUTdrN1dWenhZUFdPallrVENlK3drM0srdz09IiwibWFjIjoiNzJhOWU4YzdiOWE0Y2I1MzJiMTg3NzA3ZDEwMzc2NjgwYTExYzhiM2EyYzEwM2JmZjJkNTcyNDVjYTU0Yzc1OSJ9; 35 | expires=Sat, 09-Dec-2017 22:09:46 GMT; Max-Age=7200; path=/'] 36 | Vary: [Accept-Encoding] 37 | X-RateLimit-Limit: ['25'] 38 | X-RateLimit-Remaining: ['17'] 39 | X-RateLimit-Reset: ['1512851037'] 40 | status: {code: 200, message: OK} 41 | version: 1 42 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_extracts_get_user.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/extracts/QLG39RN2AFPMR6WLTPLW00000/user?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA4yPvW7EIBCEX8XaJo0xYCKfQndKypS5joaYjYMOYwRLLOXkd4981+VHSjkjzTcz 15 | F3CWLOgLRD+eo50RNJwi2Rld87TLFoKPZ9DwTpSKNtzwdV270cZoX33JmJZMpRuX2XCbvOEfshOG 16 | 14K5GF5vKOZuKLJT8HHveEa6K82E1Kzos+ughZrD/2pSXt58wB/0EuoEGr65Y0ZL6I60v3SWkPz1 17 | ZS/kPZM9E4emV1oJrQ77Qj/j53KdeHp5hK2Fmtxf+YGJgSnRyEGrB93LX/Lb9gUAAP//AwCmoeFa 18 | YwEAAA== 19 | headers: 20 | CF-RAY: [3caa9aa1e84322e8-LAX] 21 | Cache-Control: ['private, must-revalidate'] 22 | Connection: [keep-alive] 23 | Content-Encoding: [gzip] 24 | Content-Type: [application/json] 25 | Date: ['Sat, 09 Dec 2017 20:09:46 GMT'] 26 | ETag: [W/"e203737e2ad6a8c846bd70fa453e9a73-gzip"] 27 | Server: [cloudflare-nginx] 28 | Set-Cookie: ['__cfduid=d9e1ce2968cb55e6c53a48d380301ba721512850186; expires=Sun, 29 | 09-Dec-18 20:09:46 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 30 | 'XSRF-TOKEN=eyJpdiI6IkVPWnVTMTRqa3hiVXhLaWRvTmRpZ3c9PSIsInZhbHVlIjoick5lVnRoK0pHN3UyZHV1dDdYY3BySWlmcEZXYkpGYWE0d05oTDN2UHdCWFhDNk5PXC9ReDk5MExNdkhyMTNMeng5YW8ya2szWG1RSWIzQUJqdXprT0t3PT0iLCJtYWMiOiI4MDg3Y2ZjMTU4N2I3NjIwNzkxZTllNDc5MzRmNjA0OTc0MzZmNjhhMDU3Y2E4OTlmMmU5YTEyNjNiMTczNDc1In0%3D; 31 | expires=Sat, 09-Dec-2017 22:09:46 GMT; Max-Age=7200; path=/'] 32 | Vary: [Accept-Encoding] 33 | X-RateLimit-Limit: ['25'] 34 | X-RateLimit-Remaining: ['16'] 35 | X-RateLimit-Reset: ['1512851037'] 36 | status: {code: 200, message: OK} 37 | version: 1 38 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_flowers_get.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/flowers/AHZ7H4N6467FVUDY3DAY00000?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7RTXW+bMBT9K+g+AzaBAvFbtijK0/bSVOtkqboYk7ARcG1TxKr898lJm3RaW1VM 15 | u0/XH/ecc6+PH6FEi8AeocW9BAZft1p6n6TWoxd4q6YbpDbgQy+UAAaL9fdsnXxJkzRb3WyWt/Fy 16 | cUtdgA9N3f4EBjtrlWGccDIMQyiwbbGojZaq09aEottzgqrm5CEKKSfViYGT95Dv9cdwT2DB0x4n 17 | 9zoQXSk52aFSY4ljUKHem7/X3VbLoHBNB8lZU6jaLfhQoHYg0xQ8Ff+bgl4309gnkYIP9R63H2z4 18 | eNW8eMeYk6pvmrs4KjBOaVXlVxIxL7JEzq9ijLKZSBOaV2maZFjIWfhDuR6V7speSP3CiWundomj 19 | t3JqLx6k5zg65bKc6sFnbsPJ29gHH+yonK7LnIzVWLevfp6L3Pm3m012NDb9M6bKPbEaTt5GPvjQ 20 | YHEtjQVWYWOkD3YnzrkoynOu5UMtB+OaEF3fWmDRf/vKnDyzHXwQWqKV5cI66hKttPVxhjMapQGd 21 | BVHuRXMWZyzJwAd3+Ktr3YXN9WdX36vynfp5QHMvylhMGU1fqT8cfgMAAP//AwBD3V4D+gQAAA== 22 | headers: 23 | CF-RAY: [3caae2375fa25f87-LAS] 24 | Cache-Control: ['private, must-revalidate'] 25 | Connection: [keep-alive] 26 | Content-Encoding: [gzip] 27 | Content-Type: [application/json] 28 | Date: ['Sat, 09 Dec 2017 20:58:38 GMT'] 29 | ETag: [W/"85edd271edf011e39e9a47241b5fe9cb-gzip"] 30 | Server: [cloudflare-nginx] 31 | Set-Cookie: ['__cfduid=df83bc6c2160e537796a171094c1b3b281512853118; expires=Sun, 32 | 09-Dec-18 20:58:38 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 33 | 'XSRF-TOKEN=eyJpdiI6IlpyNmNXZm5iWmEzWWgxcjRPcVJcL2J3PT0iLCJ2YWx1ZSI6IkdiaFYydUdxZmhPR0N0VGw5MmhPMVF1dUlHTDlla1BITzlDWEtPbkthY1ltQUdsTm5RSk1CeWFZUlJodXdKQmZjUURudVJkczk3b1pBUDdQOG85emV3PT0iLCJtYWMiOiJjNjhmZmZjMGVlN2M5MmE5YzE1MTU2NTgwNzMyOGJjODY4MjY0MjVmMDIyZTdiOGZlMDg3M2I4MWRlZWM4MTA5In0%3D; 34 | expires=Sat, 09-Dec-2017 22:58:38 GMT; Max-Age=7200; path=/'] 35 | Vary: [Accept-Encoding] 36 | X-RateLimit-Limit: ['25'] 37 | X-RateLimit-Remaining: ['20'] 38 | X-RateLimit-Reset: ['1512853750'] 39 | status: {code: 200, message: OK} 40 | version: 1 41 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_flowers_get_available.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/flowers/YYRZDWGVU22WJVPGDJ7J00000/availability/geo/37.7749295/-122.4194155/10?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA9yVXW+bMBSG/0p0riFgAyHxXdaqrXo1bWmrrlTRqXEAldjMNou6Kv+9MvlQsvVD 15 | ibaLjSv8cs55j48fmWfI0SKwu2eQOBfA4AJ1LfyJaXt+76xWC6ENeNDyhgOD29sv305vzq+vKL25 16 | vP58fnqZXobuAQ/qSj4Cg9LaxrAsyILFYtHnKCU+VEaLRmlr+lzNswCbKgt+kH6YBbOVQxa8V9k+ 17 | Na6zVaxzUhxtpSSwbddWP30afx0f20ZemUZIg7oSJgs4ZoFB6c80Sl4ZrrLA6qcHNOjqowUGUdpP 18 | U5KSYeIkWQADn1Daj+NoOKIjWHrQ6IoLYLKt6/ViWmI9mxYa5/vySgFC+t12V6KoitKWzirZlb+3 19 | qK3QwCANd/WutGqlswQS733byHS4lrkWaEU+tm6COVphq26KNCSJH6Y+jXokZdGAJZEbfzUXP5V0 20 | AVeTE7e1tsnfzifUD4nLpylLBq/kL71/HLYzIepzpfK/RttMiLpYG2xxSwYkjoa/4BbRZDCkR+EW 21 | HkTbIHmbNvo6bfRj2mJHGyG9kHS0kENp28mPEkbj/5G2iahFobEpexcCa1v2ToS0q+A/A5/Cxxpl 22 | ngV24+SXnZPPt04bCodkRGMS71NIB2mU0OS4S48eguFvddew7ep70vs3HfXJyLETRywJD7/pPsxf 23 | 3nswF+7/+gwNFpXcnq1VFmtgkQdctdJ2b43Q0wYLAYyEHvBWayHtRvFWKd3SdGt3+gbY3f1yuXwB 24 | AAD//wMAq5mwXscHAAA= 25 | headers: 26 | CF-RAY: [3caae396b9445f63-LAS] 27 | Cache-Control: ['private, must-revalidate'] 28 | Connection: [keep-alive] 29 | Content-Encoding: [gzip] 30 | Content-Type: [application/json] 31 | Date: ['Sat, 09 Dec 2017 20:59:35 GMT'] 32 | ETag: [W/"d128b967e65b83378860df3953714675-gzip"] 33 | Server: [cloudflare-nginx] 34 | Set-Cookie: ['__cfduid=dbb993c2246ac439036297395aa6909ae1512853174; expires=Sun, 35 | 09-Dec-18 20:59:34 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 36 | 'XSRF-TOKEN=eyJpdiI6IkVUbW9KaG9hbnZCMGhIXC9hVk5qOFF3PT0iLCJ2YWx1ZSI6InhyUXpobWJGMU12RzNpSDdpbEg2bXZSSXdjdTNYbUpcLzcxUlBZd1RSaFE5OXNjXC9rNE5DbW15aFVFeXozOXVrUStzcVcwaUlQYW5ZT3JaRDcxUUs1ZXc9PSIsIm1hYyI6IjRjYzg2MDRjNGZiMzg3MTM1YTUxYzlkOTczZGQ2ZGE1N2RhZjExZTI4NWI0M2Y3NDI3ODRlMmMyNTY1NjhkMWMifQ%3D%3D; 37 | expires=Sat, 09-Dec-2017 22:59:35 GMT; Max-Age=7200; path=/'] 38 | Vary: [Accept-Encoding] 39 | X-RateLimit-Limit: ['25'] 40 | X-RateLimit-Remaining: ['15'] 41 | X-RateLimit-Reset: ['1512853750'] 42 | status: {code: 200, message: OK} 43 | version: 1 44 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_flowers_get_effects_flavors.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/flowers/AHZ7H4N6467FVUDY3DAY00000/effectsFlavors?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA0yN2wqDMBAF/+U8S4mllJKfka1udUFjSDZeEP+9lGLI6wxnzoGOlGAPcPLDHIRg 15 | 8boZYwwqtIFJZRHdYVGbjGmcxPWweFzIpentOMaSkfesotz0JA4Wz0t0YW+mOelQwk9I/5/8Hr20 16 | O6xL41iBKejw0/es5xTKQFyZtQReHF9zcpuw5lrgRXiNsPV5fgEAAP//AwD/3w9NAwEAAA== 17 | headers: 18 | CF-RAY: [3caae3996c395f8d-LAS] 19 | Cache-Control: ['private, must-revalidate'] 20 | Connection: [keep-alive] 21 | Content-Encoding: [gzip] 22 | Content-Type: [application/json] 23 | Date: ['Sat, 09 Dec 2017 20:59:35 GMT'] 24 | ETag: [W/"5f8e19c1297b17c8e0e000a481be7b98-gzip"] 25 | Server: [cloudflare-nginx] 26 | Set-Cookie: ['__cfduid=ddb025a4093df16511e80d4fbc75a7c321512853175; expires=Sun, 27 | 09-Dec-18 20:59:35 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 28 | 'XSRF-TOKEN=eyJpdiI6IlE4K0VVVm9sNG0wcGRoRm1tbHhtZGc9PSIsInZhbHVlIjoiY3BLRStvTHQyaE5qdlc1UXdZRjVCVUJzZ3VMbnk0Y2w1bkpLNHVQXC9rUm1UMk9Cb09WajRXMDBGVUl4bFwvMmxja1ArcmZ3blJORkF4UEh2c1g0WkdVZz09IiwibWFjIjoiYTVhNTYzMWY3MjIxMjA4N2RjNjI4M2VjMzE0ZDJkYjY0YTdiNGYxZjg0MWEzNmM2NjQwZjAwMjZjODNmZWI3YiJ9; 29 | expires=Sat, 09-Dec-2017 22:59:35 GMT; Max-Age=7200; path=/'] 30 | Vary: [Accept-Encoding] 31 | X-RateLimit-Limit: ['25'] 32 | X-RateLimit-Remaining: ['14'] 33 | X-RateLimit-Reset: ['1512853750'] 34 | status: {code: 200, message: OK} 35 | version: 1 36 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_flowers_get_producer.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/flowers/AHZ7H4N6467FVUDY3DAY00000/producer?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7yTyW7CMBRFfwW9tRMnIXJodlUR6geUrixVDw/gNoNxHFKK8u+VKdBNVbFo8c7D 15 | PUdXTz6ARI9QHqDBWkEJj2jtfo77yQJd3QGBXlgBJSSXVSyel/PvLRCoTPMGJWy8t13JKafDMMQC 16 | mwZXpnPKts53sWhrTtEaTndpnHBqXSt7oVzH6W/srbuOfMZFp1NON6GJxH2kQxNOty4SrVShkqv+ 17 | BgoETI1rdR3t+LQ7UrWpFKc5p7qvqpdcTplIC6lmeqXZKitmeaZYgWLKNNM6R8ESzTCJX+0aCDi1 18 | M2rowtBE2zceyuQfZ8Dp2TcSUO/eofC3c1+EQS7NqlI3dJ98I4GvwA17X4QjAeEUeiXvfbBL9Mqb 19 | 41fNkpRFSRals0l6V05Zmd4BgXD50TbhwfLpIeR7K6/L58UP+XH8BAAA//8DAHi7gCckBAAA 20 | headers: 21 | CF-RAY: [3caae39b0afb5f75-LAS] 22 | Cache-Control: ['private, must-revalidate'] 23 | Connection: [keep-alive] 24 | Content-Encoding: [gzip] 25 | Content-Type: [application/json] 26 | Date: ['Sat, 09 Dec 2017 20:59:35 GMT'] 27 | ETag: [W/"f79f0159594ec71dae47c54faa44833c-gzip"] 28 | Server: [cloudflare-nginx] 29 | Set-Cookie: ['__cfduid=d6e898ba7e667145d5773e22e629670011512853175; expires=Sun, 30 | 09-Dec-18 20:59:35 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 31 | 'XSRF-TOKEN=eyJpdiI6ImRZM2FMS1Q1UDRDZStmTXNYOElaOFE9PSIsInZhbHVlIjoiRVptdmtIWGtUN29zT0Vwak5lUFhBTTkyM1BwK0cxQ3hldk00N1ZtNndoSFE3MGhueGpnazZqZWYxZFBEeFZYYThneU5DeWF0Z3ZDQjUyNXlvVWJ2XC9BPT0iLCJtYWMiOiIwNWI3YjVmZjA4NDMxZjYzODI3ZDA4ZDZkNDFkODM0MTRkMGU4Yzk0NGFiNmIzMTE5NDA1YmE2MTIwMTVhNzk4In0%3D; 32 | expires=Sat, 09-Dec-2017 22:59:35 GMT; Max-Age=7200; path=/'] 33 | Vary: [Accept-Encoding] 34 | X-RateLimit-Limit: ['25'] 35 | X-RateLimit-Remaining: ['13'] 36 | X-RateLimit-Reset: ['1512853750'] 37 | status: {code: 200, message: OK} 38 | version: 1 39 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_flowers_get_review.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/flowers/AHZ7H4N6467FVUDY3DAY00000/reviews?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA6SSQW7bMBBFr1L8NWORUi073BW5QrqKAmNMjW02EklQI7upobsXtJusA3THT/K9 15 | T4BzRU9CsC9XDD68weIkkibbVV11uVxWjkKgvZ8yp5hlWrk4dhUl31Vns9Jdlfns+TJ1ldubTV+3 16 | /Ya3m41bEzW61Vxv13TYM9f1et3Q1phHKMx5+FrPp7zWpu0q3XSVNl+v6qpfe5eje2MRKPCcTjF7 17 | gsUWCi4ziT97eYeF0VBI5MMu8+D5ABvmYVCglFi88O5IPsCiLSANow9HWHyHAoXfnovjDkzJu8/A 18 | lOVU9DUUDnm+d5XyKc75n67P77sxznL6oG4P4/6HwF7L77D4kYtEm/ZBNw/afKsb27S2Kdpy+CeG 19 | cuHn8xMWhTn1/8Evrwojl5G4ItHRBxIfQ0kShQZYo+DiHOS2Spx3iY4Ma7SCm3PmIB876o7c4nTL 20 | ZcQm2JfXZVn+AgAA//8DANbyrnZ6AgAA 21 | headers: 22 | CF-RAY: [3caae238ff7c5f8d-LAS] 23 | Cache-Control: ['private, must-revalidate'] 24 | Connection: [keep-alive] 25 | Content-Encoding: [gzip] 26 | Content-Type: [application/json] 27 | Date: ['Sat, 09 Dec 2017 20:58:39 GMT'] 28 | ETag: [W/"7038518f6917b287c5a0cabab0dc6fdc-gzip"] 29 | Server: [cloudflare-nginx] 30 | Set-Cookie: ['__cfduid=d1252b8313522eec93347e7f87fafa6341512853118; expires=Sun, 31 | 09-Dec-18 20:58:38 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 32 | 'XSRF-TOKEN=eyJpdiI6IjIxYXd1VWMwNVlES1NET2NiYU1adXc9PSIsInZhbHVlIjoiWWRYTG1rSzhZbGxVR0pxcE1xdDA1U3EwUWFKWGJIK1dkVVpaem1vYmlmWXdUVGptT0tVXC9YNWc1XC9NR09nNEpLU0VnSzNGTmhKaVBreENCd0hlNVA0Zz09IiwibWFjIjoiNjYzNWM5ZDdkNjg1MDdmZGEwY2ZlYmE2YzVmY2I5YmFjNDAxMWNkNTIyODg4NWJjZGNjMzliYjY1MDA3ZGQ5NyJ9; 33 | expires=Sat, 09-Dec-2017 22:58:39 GMT; Max-Age=7200; path=/'] 34 | Vary: [Accept-Encoding] 35 | X-RateLimit-Limit: ['25'] 36 | X-RateLimit-Remaining: ['19'] 37 | X-RateLimit-Reset: ['1512853750'] 38 | status: {code: 200, message: OK} 39 | version: 1 40 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_flowers_get_strain.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/flowers/AHZ7H4N6467FVUDY3DAY00000/strain?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7ySUW/TMBDHv0p0z0kdZ2ma5K1sQkUIeIAitBmha3xNDamT2W6zMuW7Iwe6jWlD 15 | E4Ldo313v/vf/a9BokMor0HjlqCEd7Wh4AUZc4AQdlVXQQnFp4/LWfo2S7P494AQGqW/QQkb5zpb 16 | CiZY3/eTCrXGlbKGutY4O6narWDYKcH2fBILZp1Bpa1gf+p8aZ7W92ez6NebYBvsuoPEQ7RGs7WC 17 | tbWhaOUVRalglyaqWkkTu6+9QNP8ewiEoLZY09M6j6n2zk5ywda7pvmSS5nJlUyLFZ/yZMpnCRZZ 18 | wos4z9Y5T9KMOBKfriZfOy/FEsnTdtuhPtw558LPeYaH4KWf8/ak88X5bBE/EH99UiIZVSNfeTmP 19 | A4YQatLkVGWPg9qj8a6CV7ZBLYM37U47VDp47wz242KD+breoFb3fLksFsvX9xjBVTD+naVFcv5s 20 | nhXsRtcwQmg0wcXnEKqNaqQh7QVXXhqU8X+c4wY3hGBor6i3z0Q+0oYQKkPoSM6dR0t05NRoySTm 21 | 0yieRUkR8LzkvEynEIL//N5qn7D8cOrrd518vJ4nUVwEyUkZz8qT/IH6YfgBAAD//wMAoFbtc9sE 22 | AAA= 23 | headers: 24 | CF-RAY: [3caae39d1c935f3f-LAS] 25 | Cache-Control: ['private, must-revalidate'] 26 | Connection: [keep-alive] 27 | Content-Encoding: [gzip] 28 | Content-Type: [application/json] 29 | Date: ['Sat, 09 Dec 2017 20:59:36 GMT'] 30 | ETag: [W/"5ade8f81552c0bfee2135ff2d071b5ce-gzip"] 31 | Server: [cloudflare-nginx] 32 | Set-Cookie: ['__cfduid=d574bcb590d7b339e4f2468e8d1955a341512853175; expires=Sun, 33 | 09-Dec-18 20:59:35 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 34 | 'XSRF-TOKEN=eyJpdiI6Ing1bnhhbEhPMlwvNkoxR2dsVklpRzV3PT0iLCJ2YWx1ZSI6Iko0YndKc3VaTVJNQ2NYYXQwRjM5a0dYTEhFWVhyUWtibkJwWnkyQXg0Tk1YTHY1d3RjbThqR3duMUpcL2JERnRMOEp3UGpsRFRERE5vc2FHVWRyQkdXQT09IiwibWFjIjoiZjI0MjFhYjU3NmQ5NDJhZmFjMTc1MDUyYTMzNTYzYTIyMzY1NzhmYzlkMDFlMmVlNjVkOGRkMzBjOTMxNWI5MSJ9; 35 | expires=Sat, 09-Dec-2017 22:59:36 GMT; Max-Age=7200; path=/'] 36 | Vary: [Accept-Encoding] 37 | X-RateLimit-Limit: ['25'] 38 | X-RateLimit-Remaining: ['12'] 39 | X-RateLimit-Reset: ['1512853750'] 40 | status: {code: 200, message: OK} 41 | version: 1 42 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_flowers_get_user.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/flowers/AHZ7H4N6467FVUDY3DAY00000/user?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA4yPQW7DIBBFr2LN2jaQ0Dpil/YKzY7NBFOHGgOCcSwl8t0rZ9eolXqA//57d+iR 15 | ENQdgjNjwMmCgq+zydGMlghq8C6MoOBClIrSTLNlWVqDIeDZlWxTzFRaEyfNMDnNrqLlms3F5qLZ 16 | DxDh4F3Y+G8eby4MFV1sdfQ4Rahhzv5/LynHT+ftE7z4eXg2N9ki2f5IW16PZMk98nZcyIbLRuwr 17 | 3inZqf3rpucme4sPv9PHO6w1zKn/a981gje7Q8WlEgf1In/Zr+s3AAAA//8DAGcOvFJcAQAA 18 | headers: 19 | CF-RAY: [3caae23add515f75-LAS] 20 | Cache-Control: ['private, must-revalidate'] 21 | Connection: [keep-alive] 22 | Content-Encoding: [gzip] 23 | Content-Type: [application/json] 24 | Date: ['Sat, 09 Dec 2017 20:58:39 GMT'] 25 | ETag: [W/"e3ed49207ec6e5c127aad9b0dab63b35-gzip"] 26 | Server: [cloudflare-nginx] 27 | Set-Cookie: ['__cfduid=d2965c74d2a9e3c9a783a29d4582215951512853119; expires=Sun, 28 | 09-Dec-18 20:58:39 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 29 | 'XSRF-TOKEN=eyJpdiI6Im9lbzVkdis2cjdtZ3Myb3lXYmd2Qmc9PSIsInZhbHVlIjoiVGtSa2lDRHN0WU1QRVwvZjVESCsyV0dVb1FxYnpyNHhKbkhBWEtNTTBYaXdEalwvOHpoaXM1TlwvXC9yV1lBZUdQaUFDSHRhcE9vNEFtT0JLM20zeTExRGhBPT0iLCJtYWMiOiJiMWI0YjM2MWQzYTcyNzNlMjE0ZTdkNDIwOWRlMjI1MGE0NDc0M2ExNTc1NDEzY2MzNDNjY2JjYmMyODFhYmY4In0%3D; 30 | expires=Sat, 09-Dec-2017 22:58:39 GMT; Max-Age=7200; path=/'] 31 | Vary: [Accept-Encoding] 32 | X-RateLimit-Limit: ['25'] 33 | X-RateLimit-Remaining: ['18'] 34 | X-RateLimit-Reset: ['1512853750'] 35 | status: {code: 200, message: OK} 36 | version: 1 37 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_producers_get.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/producers/0000000000L6M7E0000000000?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7yTy07DMBBFf6WatRM7j+bhHUKsgB3sLKGJ7RbTNEkdJ0FU+XeUUMpDAlVCxTvb 15 | c8/R2Jo9KHQIfA8VbjVwuDY9AoFONhI4sOO6SW7Tq48tEChNtQEOj841LRdU0GEYfIlVhYVprW5q 16 | 61pf1ltBsTGC9oHPBG1srTqpbSvob+ydPY38jvMOp4JuTI+C7qwna6WnRmz5FxQQMFtc69MYc2k7 17 | s1am1IJmgq66snzIijiWOl0WqwKTNElzxoJMZRioMF2qWKVRkmUR5v5TswYCVvdGD+30LbLuKgc8 18 | YGd8cEHfhSMB/ewsSvdZfl73UTjJlSlK/aXx7Lzyg3Ak8Bb4x8aPwpGAtBqdVhdusit02pl5HEMW 19 | xB5LPZYvwpDHAQ9zIDBdvtTVVHB/dznlu0b9lF96QeixcMFyHkV8Hq/v+XF8BQAA//8DAC9hFwUI 20 | BAAA 21 | headers: 22 | CF-RAY: [3cab11169ddb5f57-LAS] 23 | Cache-Control: ['private, must-revalidate'] 24 | Connection: [keep-alive] 25 | Content-Encoding: [gzip] 26 | Content-Type: [application/json] 27 | Date: ['Sat, 09 Dec 2017 21:30:38 GMT'] 28 | ETag: [W/"a328872ec1ec071b58636f15912b08a2-gzip"] 29 | Server: [cloudflare-nginx] 30 | Set-Cookie: ['__cfduid=d7e485dfad7e62ceeb7c7678ed6d17baa1512855038; expires=Sun, 31 | 09-Dec-18 21:30:38 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 32 | 'XSRF-TOKEN=eyJpdiI6Iks2WGZaVlNuenRBSm9SZkdTbkdnV3c9PSIsInZhbHVlIjoiQ3pDdWxzMDh0enZNXC96YWZGeGUySHNENDR5NE1sZEhNc2pkbEVSc0VwNTZoMkt0aUpQYzBUQTVEdzVBZUFxeWRnSGFEV0E3UVZWZ29zXC9KSEI0TjQ0QT09IiwibWFjIjoiOGQyZjJiNWIyNmYzY2FiNWE4ZDdjMWUxMWZlMDgzZGEyMWJhMWM4NWE5YjViOTYzMzllZmRlNGQzMjU2NzlhNSJ9; 33 | expires=Sat, 09-Dec-2017 23:30:38 GMT; Max-Age=7200; path=/'] 34 | Vary: [Accept-Encoding] 35 | X-RateLimit-Limit: ['25'] 36 | X-RateLimit-Remaining: ['24'] 37 | X-RateLimit-Reset: ['1512855938'] 38 | status: {code: 200, message: OK} 39 | version: 1 40 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_producers_get_available.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/producers/0000000000L6M7E0000000000/availability/geo/37.7749295/-122.4194155/10?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA+yZbW/bNhCA/wrBD8MGWBZJvdkEiiJxk3Rtki5ZmnabhuBCMzIRmdIoKlka+L8P 15 | lNesSlonnqEgLqJvd9Idj7oHdyfqGo/BAuZ/XGMNU4k5PpLGANqqSiOrqkCbysoKjQqwcoyURq/A 16 | nKPRpBBFDlbiHq5FKTDH5ObajfeSrQ/s1eFBI+IezpU+xxxPrC0rnvqpf3l52RegNZyqysiyMLbq 17 | i2Ka+lCq1L+gfZL6cqxOc1ml/iLP9qp0Mc+fdSsVAqwqNOY3+/l1e/vdzs7/jWKsqlLqCoxyoQhI 18 | /Qq0d2ZAC1WJIvWrs7Miy5x7sJjjIOknCU0CSp1KZ5hjjzLWD2kchWSIZz1cGiVcYDTqN3to5JMJ 19 | 5GcnmYEp5rrO88/quxqpsomdtHV/1WCsNG1l47GotVvsS31LJYx0md2w7o2NwUqrmrfGCA09Sj0S 20 | IDrkYcCZ25C7+anQ7oH3RyO3mbocf8s+cvY0cfYB4ZR9xX7Wu0lTmyv0Y0ym2U/fxCvZjQ/2O8Gr 21 | 5Xmt8SJPG6/Io8QjDDHGo4STYBW8Ih7cg9ee0hb9bFQ1QSMjYYr2VN7ijQ4WAhdvBPvbnQDX8rzO 22 | wLEnDxwZeiREhPIw4WG0AnBswFm4GLjNHMT5qTTmCt0ubfeg9vFw++C4E9Ranp9RezTUwtVQC+L7 23 | alu+ROsMtl7vvekEr5bn59b5WK2Txiu2zmAxXkegM2mUlssWst9eJ78fdUJay/NzIXusQhYFqxUy 24 | OlhM2jFoleeARhNQyw5oO1vHo24GtJbnZ9jWZUALyD1l7Ts753grLUwBjYo8l8KqC9kZgefNSp5o 25 | rfQFjINgOLgFI2NJHK7T4UfskchjEaLu05SHZFkWH2B/h8XNvJbzL4bbMDa18Af0YaKsfACU+7tv 26 | jj92AmXL80Nq4S8bh6PuSmEJRrThiwfDO/DRkNFwrY7eIo8MvIAiRnnIVhvwKOUs/v4HvCfK2WB9 27 | Om7EKe2Csz97eCrdL4ZrXEKm9E3qbGEhxzwgcQ+LotYWc0p6uJTmpIRMziVRGyO1/azpza0ascI8 28 | oPOUVw0K8m+7dO5LU4xrIc1dBP8TUx8uQOVwqnJlr1I/k0XqNxSEQzaMUv/f9A9DGkWpT8lLF94L 29 | hmez2ewfAAAA//8DANE9/FxhGQAA 30 | headers: 31 | CF-RAY: [3cab1ca8bbdd5f6f-LAS] 32 | Cache-Control: ['private, must-revalidate'] 33 | Connection: [keep-alive] 34 | Content-Encoding: [gzip] 35 | Content-Type: [application/json] 36 | Date: ['Sat, 09 Dec 2017 21:38:33 GMT'] 37 | ETag: [W/"7c06a7f4b2ddd417965b3950973ae5c7-gzip"] 38 | Server: [cloudflare-nginx] 39 | Set-Cookie: ['__cfduid=d55d9b44857c48d73516cb6edd2aae2b11512855512; expires=Sun, 40 | 09-Dec-18 21:38:32 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 41 | 'XSRF-TOKEN=eyJpdiI6InYyWU9YZ2lweTkrUHNEelJEM2xaSGc9PSIsInZhbHVlIjoiU1R6clhUMkQyRkJTUERmSVBZUWhIUkNWUVNvVE11dUpLRUFPRmh2ZW1vcUdETjhuYWkwMjJJdXdVYytKN1NcL2hWeHpTQnZwQVwvNENBQ2xwMTQwaWpvQT09IiwibWFjIjoiNjVlZjE0Y2M5ZmJiNmFjMmY2YzdjMjk3Y2VmZWIzZWE5MDliMzAzMjAyYjJhZjRjMTY1YjgxZjAxMjI5MGU4MSJ9; 42 | expires=Sat, 09-Dec-2017 23:38:33 GMT; Max-Age=7200; path=/'] 43 | Vary: [Accept-Encoding] 44 | X-RateLimit-Limit: ['25'] 45 | X-RateLimit-Remaining: ['8'] 46 | X-RateLimit-Reset: ['1512855938'] 47 | status: {code: 200, message: OK} 48 | - request: 49 | body: null 50 | headers: 51 | Accept: ['*/*'] 52 | Accept-Encoding: ['gzip, deflate'] 53 | Connection: [keep-alive] 54 | Cookie: [XSRF-TOKEN=eyJpdiI6InYyWU9YZ2lweTkrUHNEelJEM2xaSGc9PSIsInZhbHVlIjoiU1R6clhUMkQyRkJTUERmSVBZUWhIUkNWUVNvVE11dUpLRUFPRmh2ZW1vcUdETjhuYWkwMjJJdXdVYytKN1NcL2hWeHpTQnZwQVwvNENBQ2xwMTQwaWpvQT09IiwibWFjIjoiNjVlZjE0Y2M5ZmJiNmFjMmY2YzdjMjk3Y2VmZWIzZWE5MDliMzAzMjAyYjJhZjRjMTY1YjgxZjAxMjI5MGU4MSJ9; 55 | __cfduid=d55d9b44857c48d73516cb6edd2aae2b11512855512] 56 | User-Agent: [python-requests/2.18.4] 57 | method: GET 58 | uri: https://www.cannabisreports.com/api/v1.0/producers/0000000000L6M7E0000000000/availability/geo/37.7749295/-122.4194155/10?page=2 59 | response: 60 | body: 61 | string: !!binary | 62 | H4sIAAAAAAAAA+yZb2/TMBDGv0rkVyClTZw/bWMJoS3rBoMiNroyQdB0Tb3UWmoH29kYU787SjpK 63 | s7JOQ0q3ovbdneInF/un8z3qDRqBBkS+3iAOE4oI6rH0wgjHIhYpaGq8wP4keYlMlMdZjAiy57/3 64 | rV67Ozjsf3HLEJkoZfwCETTWOlMksiLr6uqqGQPnMGRK0kxIrZqxmEQWZCyyLnHTjiw6YsOUqsha 65 | payvs6K22bPFm0QMmgmOyLzuTx93jsN/LWLEVEa5AsmKSmKILAW8cS6Bx0zFIrJUBjIu1EEjgtx2 66 | s91udYKgU6R4gghqYMdpethzsBegqYkyyeKiLLdZfkAZno0hPT9LJEwQ4Xma/k4vZyhLxnpczX3P 67 | QWoqq8lSUeS8eNdivpKKJQVNRzu62K4RaKpZuWWOjf2GHTRsz7Ax8Xzi4WKv2YT+FLx44KQfFt+S 68 | Z6P712PcwG0DBwRj4rT+sn5qzs9oAJylKRjhGJixBFrHXkXaQXcQ7tdCWkV5c0nDnU1CDdv1otZj 69 | XBtvJVNjI5QUJku4eSv72uHAfefVQltFeXNpa20SbK5XL2x9KiUYXZVJqpQwdpmmyghFIW4wbuyB 70 | XEDvXuY+O3vHR7UwV1He4A7nP2/ovBIabDgO8e3aL9PdFOKLIZXy+g5gD/W2gXeyf1rPzLaovO1t 71 | 6+ltbt0XafXebK2c0tzum95hLWxVlDeXrWCT2HJqHtLu9q3VXtN90z2op29VlLdecz1e03liA/CA 72 | 32ztuB/q8ZsV5a3f/D/8Zh94QiXj9JHD2OleODipBbOK8nYYW88w5j/ZzP9AOzs93j8a1MPZovK2 73 | na0HNDuoA7RvJprQ4u+AG5RBwvj86LTQkCLi2i0TxSLnGhFsmyij8iyDhM6iOJeScn2bcczZqjJU 74 | iLh4duSqVJf0kolcPfr8MylGeUzlMoZ/wsiCS2ApDFnK9HVkJVREVkmCFziBH1m3CAQe9v3Iwvbr 75 | osRXhV3n9Id+TjW5aDqdTn8BAAD//wMA+kvgwqUZAAA= 76 | headers: 77 | CF-RAY: [3cab1cae2c6f5f6f-LAS] 78 | Cache-Control: ['private, must-revalidate'] 79 | Connection: [keep-alive] 80 | Content-Encoding: [gzip] 81 | Content-Type: [application/json] 82 | Date: ['Sat, 09 Dec 2017 21:38:34 GMT'] 83 | ETag: [W/"4f35245d97cf603b257e7981d6f55317-gzip"] 84 | Server: [cloudflare-nginx] 85 | Set-Cookie: ['XSRF-TOKEN=eyJpdiI6InhIQ0lkZkw4WmhSMVBFOFcxTklKNHc9PSIsInZhbHVlIjoibDhrWWdUQ1wvU2VlMlwvMnpCXC9VR29EdHZSU0dCS0U1V0FWczBWWmNaU3FNb0xIVlhNNU1aeEZmWGNybWc5SklFSGZBRmxMaG5NN3lLcUJFSTB2aUliSXc9PSIsIm1hYyI6ImU2OTBkZWI3ZWU3MTdhMmJmNjY3YjEwNWIwZjU3MDQxY2I0MTNmNDJmNzkzMmUzZTRlNmY2Njg1ODA0OTM4YzAifQ%3D%3D; 86 | expires=Sat, 09-Dec-2017 23:38:34 GMT; Max-Age=7200; path=/'] 87 | Vary: [Accept-Encoding] 88 | X-RateLimit-Limit: ['25'] 89 | X-RateLimit-Remaining: ['7'] 90 | X-RateLimit-Reset: ['1512855938'] 91 | status: {code: 200, message: OK} 92 | version: 1 93 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_producers_get_products.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/producers/0000000000N4E9N0000000000/products?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA+yabXObOBDHvwqj1yhIAvGgd016d7027mXS5q690uksSMQ0PBXk5NpOvvsNNrHj 15 | uTpx7chprvErhNH+WbT7m13BVyRBAxLvvqIKSoUE2q/lZ2t/orVqkY0maZMigcj899L7JXp5EryJ 16 | DqdDZKMir86QQGOtm07ETuxcXFzspVBVkORdq5q61d1eWpexA00eO+d0j8RO09Zykuoudm4y/ald 17 | z/BgDQ8nY+dTi9NaqtiR+XleKdyqUslcdbGT1PIzTqbu7TXVKbJRAm1/7YZKw+y1lCZtsaHKTcaR 18 | jfISTtd0YHppFzudbiGvutip6g/Tc8M9zqRVi8Q8Ip5Oxa3jQXxlVCyG20WFav8bFtdsX9pIf276 19 | G9N1k6dQIBvNvEHi3XsbFZC8Vp1GIoOiUzbS43R+nCZycTzczPzEGLrxH3kxH7fqPFcXXf8k0npS 20 | aSSIuWiPnSu5SxulrQKt5BPda0vQSufTlWCEckwppoHFXEE8QTxko/7PL3XVX3Dy+qCfP2nkqvk+ 21 | JhEmoUUD4RLBo2/Mv7TnS/9Mgc6rU+sVFOfKwtarEopiZQAcHh1Ff5rBwpJpA1gYzxzFXe8o7no3 22 | DeNhteIdYuIbIpvhYrEwXuxkk6L44PlZFoSUKcgUY+DKTLEo4AQ4yThhHg1dIDKVex+bR67smiuL 23 | dPkOrhBMuEWI8CLhhqa50ibW71U26ZS0ntd5pS1sHdaJKnKwsHXUKtzWN5AmevPri8gMaZZMGyFN 24 | m+B85jr+2LuOi5njxoFzi/CdcmeV1rb44QN+OKcAPlMpk5J6XIILMo1mMFLKU17qulSp4AHip1lE 25 | /0PlzyKJ1ucPYZhEFuGCuoKzLfkTbsCf0aQoVF6tw58nx2+DkRn+LJneDX/KmeO758+ysFn+DFqP 26 | /PkZ+LNIok34w7avf27hz7Eq4J++sRrllWqhsPZBj61XNZxZ2Aqt+svqyufFgesZqnyumzZAnnZw 27 | Gpczp3ECeoy7Gs5wiOsvhvGznvodMugWwW1B5A8g8mkqAy9zGWEeydyEB37EQ49FkUz9wOURyWiU 28 | Bt4DBFH/wB5yETTPp++GEBVuKFy++yLoKZQ5VGv1YMfBwZPADImWTO+mBpIzx3dfAy0Lm62BBq3H 29 | GuhnqIEWSbQJfphgxnuwa3vLK1f+5dHJ6LkZyiyZNr2nvMvdZMP7yNviAwZ8QKi8QPkRZ0Qmnkpo 30 | FoUs8CEFlWSccj/yWBIm/P+9g4yoT8revx+NH4v02IQfRFDvHnsoxm9qop6NDke/mYHKkundNlGM 31 | 32sXdV1+N23UVPGxj7qzPgpRxn9IFC2SagMUMS5oYBZFIyV73FsHg4PWYd5Y+1CU/VstOFeVvOFj 32 | mqMXT5+9MQOjJdMGYFTO/MZXdnCRNziBosTF4LVhHK19A3cIpNs1t0VSNCApIpkCYEGospS4vlI+ 33 | 4xxcSEIg1HeTjPgqTdlDfMXeneWVlUKrHnCDtciuDahEI+FG90SllWHw9uTv53+ZQdGS6V2i6L4I 34 | tEPwPPLmp+DNIoU24U0oKDXBm/c2KlX/CfFX1MBpXoHO66of6VpDgQQl9tUT6Q8b1X5oprE6/WPS 35 | tqrSV2fs2aTpsJuO+yfY9Ut1eXn5LwAAAP//AwAr8swJrCwAAA== 36 | headers: 37 | CF-RAY: [3cab20eaaf2d5f5d-LAS] 38 | Cache-Control: ['private, must-revalidate'] 39 | Connection: [keep-alive] 40 | Content-Encoding: [gzip] 41 | Content-Type: [application/json] 42 | Date: ['Sat, 09 Dec 2017 21:41:27 GMT'] 43 | ETag: [W/"ac7fbea649d824d593e393e8763deaa3-gzip"] 44 | Server: [cloudflare-nginx] 45 | Set-Cookie: ['__cfduid=d72d72d752bc37a643eb4cc7186e2352f1512855686; expires=Sun, 46 | 09-Dec-18 21:41:26 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 47 | 'XSRF-TOKEN=eyJpdiI6Ik5xWFE4WThOcDFuQytjOXYxUkhXQnc9PSIsInZhbHVlIjoiRUhWZGZsekZlVVg3NVwvcDJkRXhnRWJXTzJKUGFtdGtqdmZSNVhKTWY3QnN3eDhadDZlRUFtWHk3dFBjTUF6QlhcLzBPTVA0K1FYNlAxWm1ZeXVQSjJrdz09IiwibWFjIjoiZWZhM2Y3NTNlMDlmNTk5YWJkYzljMGFjMTQwZGJkNWEwZjQ1NTAxZmJkODM2YjRhZGE2ZWRiNzNlYWVmNWE0MSJ9; 48 | expires=Sat, 09-Dec-2017 23:41:27 GMT; Max-Age=7200; path=/'] 49 | Vary: [Accept-Encoding] 50 | X-RateLimit-Limit: ['25'] 51 | X-RateLimit-Remaining: ['2'] 52 | X-RateLimit-Reset: ['1512855938'] 53 | status: {code: 200, message: OK} 54 | version: 1 55 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_products_get.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/products/9XVU7NK3PEGLAJ372X4F00000?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7RTTU/cMBD9K9Gcndj52mR9Q4hWKlXLASoOliqvMyEp3sTYDiuK8t+rLGEXqgWh 15 | rTqn8XjmvZnx8yNU0kvgj9DJNQKH0watfQjOey2DMLiwGNpeayAwKKOAw/L6x1Xx7Ty9OPv89eRL 16 | WiTX2Sc2GRDQbXcLHBrvjeOCCrrZbCIlu06uWmfR9Na7SPVrQaVpBb2PIyaosX01KO8EfQ/6zn4M 17 | eEYL56CgdzZUfYWC4hqt1JUTVG1HDG97LSPT3QCBlbRT0pEUc/X7FIPVR8IfRAUC7VrefLDlbap7 18 | uetY0HrQ+mdcxlhlZZ0olmasqJcSk7ReYJ6wMlsUeY6LoqxZFv0y0xRPAGhfCOZsbm8vEbaz7Tvu 19 | j/8mEbRO0LexRwL+wUwdmb1onbey7Q7L+5Cm2Ws7tuEn2leS/ht5JKDl6hKdB15L7ZCAb9TOV6tq 20 | 789su0AjXfO91buzxfsWN24aU/VD54Gz//cZBX2mGwkoi9JjdeIn7kp69O12zQmL85BlYZIG8ZLn 21 | KWcpEJguf/fdlHB1eTrVD6Z6q34RsmXIyiAueMp4Xh6oH8c/AAAA//8DAMD8wwS/BAAA 22 | headers: 23 | CF-RAY: [3caaa1120eb353a2-LAX] 24 | Cache-Control: ['private, must-revalidate'] 25 | Connection: [keep-alive] 26 | Content-Encoding: [gzip] 27 | Content-Type: [application/json] 28 | Date: ['Sat, 09 Dec 2017 20:14:10 GMT'] 29 | ETag: [W/"668cdc7a17940cb3f279abd8a130f827-gzip"] 30 | Server: [cloudflare-nginx] 31 | Set-Cookie: ['__cfduid=dfba8c34d81e4650736bc8e291b3168491512850450; expires=Sun, 32 | 09-Dec-18 20:14:10 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 33 | 'XSRF-TOKEN=eyJpdiI6ImxVc0lmV0srVXNnWVBqd0cxdWY2cHc9PSIsInZhbHVlIjoibTdZU1FVbnFZM3NzQzh0NjhxcVVMSzNyZHdhQjNONDBjb3hrZHdKWVIrTEd2MldjTmp1emRvdVRkRzBUVTNuT2VlNGJQOWdaQkp3Rzd6WU1iTnVoU3c9PSIsIm1hYyI6IjA5YmViMzFlM2I1ZjA3ODlmNGQxYTM2ZGU1ODc2NWYxZjZhNzhkMTNkM2IzNGJhMTMxZGVlNjg1ZjU2N2Q2ZmIifQ%3D%3D; 34 | expires=Sat, 09-Dec-2017 22:14:10 GMT; Max-Age=7200; path=/'] 35 | Vary: [Accept-Encoding] 36 | X-RateLimit-Limit: ['25'] 37 | X-RateLimit-Remaining: ['9'] 38 | X-RateLimit-Reset: ['1512851037'] 39 | status: {code: 200, message: OK} 40 | version: 1 41 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_products_get_available.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/products/0000000000C6FZLK664400000/availability/geo/37.7749295/-122.4194155/10?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA9yXXWvbMBSG/4rQzW6sWF/+iO7SwDZYL8a67WJ1Kaeympg5sifJLWnJfx92mizJ 15 | ylgLgba+8nnR0XskPejY97iEAFid32MLC4MVPq0ai06gXiCCJGrucIQ73WqsMN0+0/T9j9NPaSrl 16 | EOII15X9iRWeh9B6VcRFfHt7O9JgLVxV3pm2ccGPdLMoYmirIr5hI1rErWvKTgdfxP+aOizbvq6H 17 | wb1XoyFUjcXqT9FQLtF0DiEYV5vlO49OmxvjnltYWfnWWA+uMr6INRSxB0uuHVhded0UcQ3lkuit 18 | nyf1xg4CVlhkoyzL0zxjvWRnWGHCOB9JzrjkEq8i3LpK95XzZDSscogv51BfX84cLLCyXV1v5L8V 19 | U83mYb6v/erABeP2xWHGprO92a6+J2lnIJhyEvotLSGYUA3byilLCB0TKhDLFZNKiv5AqoW5a2w/ 20 | 4NvXab+Yri3/Jz9TNHskfxW9bvjOPk++TI+Gmm/B6X2y0nw8zg/IYpIzOd4lS6QvmyxJaELYGHGm 21 | EqZE9lSydvOlWp/WGyPrBNwVuCWaNuDD0Qi7WrsQvXHZkpazsUjEAWk0y8aC7ZIm6SsgjdOeFCkU 22 | y59BWkYEQ5QqyhRjb5G0ydnkiIB5OLjBaJYnB1yJPGFyrzeKF94b11wxRLmiQgn5VK5SQgVhFHGq 23 | klTJ9C32xsn3Cbr/CLYkUwfXwZRo+mCOPjRN6VfHa5xwA2TeO+u1M9lMSWa98x6RScqkOOypgidp 24 | zl9TT00JZYTmiAvFMyX5M4hkhKfD11qi5KM33UWEF6b/Z7jHLcwquz3y0ASosUoirJvOhuGtNe6y 25 | hZnBitEI6845Y8NGidYpQ+iHuCfBY3V+sVqtfgMAAP//AwBNlcGQmwwAAA== 26 | headers: 27 | CF-RAY: [3caaa114de7a7936-LAX] 28 | Cache-Control: ['private, must-revalidate'] 29 | Connection: [keep-alive] 30 | Content-Encoding: [gzip] 31 | Content-Type: [application/json] 32 | Date: ['Sat, 09 Dec 2017 20:14:11 GMT'] 33 | ETag: [W/"3f564109a362b46a5f23fc376890ef84-gzip"] 34 | Server: [cloudflare-nginx] 35 | Set-Cookie: ['__cfduid=d4890ca4d39df16ac687299c8fd1ddd881512850450; expires=Sun, 36 | 09-Dec-18 20:14:10 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 37 | 'XSRF-TOKEN=eyJpdiI6IkdCR2djK1crRk9jdDV1cUIwWnpMMkE9PSIsInZhbHVlIjoiZFRmeGVFQ08rOElycktSUHFNMzU4N2hBZmhacUN4UFNKUlVFM0Z4SzZwTlZPelBFOG0zNk52ZVl2bzF6ZXVlMUcyT25SQXJwUUZ5ekZha2REUFlRZXc9PSIsIm1hYyI6ImRiYmRlMTEzYzhjYTdhMGY3NjdhZjI0ZjQzZDVjM2UxYjViYmQxMmE2ODc0NDJjMWIwMmZjOWYxYzE4MTVhMTMifQ%3D%3D; 38 | expires=Sat, 09-Dec-2017 22:14:11 GMT; Max-Age=7200; path=/'] 39 | Vary: [Accept-Encoding] 40 | X-RateLimit-Limit: ['25'] 41 | X-RateLimit-Remaining: ['8'] 42 | X-RateLimit-Reset: ['1512851037'] 43 | status: {code: 200, message: OK} 44 | version: 1 45 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_products_get_effects_flavors.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/products/0000000000C6FZLK664400000/effectsFlavors?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA0yMQQ6DMAwE/+IzqiLUUz6DXHCJJXAix4EixN85JfQ2O6vdEyY0BH8ClRSiMoKX 15 | siwdjEpovLEdzeCysszgoX855xx0IGX9COUMHt7VYUpkbDTMyFK3kx7DGouFKr5a/q5z4rEFQrXw 16 | VLFo453IakgsVBnlx/TcKW1MewbfX9cNAAD//wMAQQfwZuIAAAA= 17 | headers: 18 | CF-RAY: [3caaa11a4fb713d1-LAX] 19 | Cache-Control: ['private, must-revalidate'] 20 | Connection: [keep-alive] 21 | Content-Encoding: [gzip] 22 | Content-Type: [application/json] 23 | Date: ['Sat, 09 Dec 2017 20:14:11 GMT'] 24 | ETag: [W/"4ad2879dc10d7b2ad4bd0043565770b1-gzip"] 25 | Server: [cloudflare-nginx] 26 | Set-Cookie: ['__cfduid=ddb147f27c6e561002df1cc6a0cb196d61512850451; expires=Sun, 27 | 09-Dec-18 20:14:11 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 28 | 'XSRF-TOKEN=eyJpdiI6IndWYjR0MFdPd0tVaVhsTUkwVXhCcGc9PSIsInZhbHVlIjoiXC9TeTJ4RCtKOHJSdUQ2c1dHNWVEbWhEWVgzV3BVSXJCN1wvK2ZDM2srUTBTQ3ZMUmdHdjNlRWl4cVg1RUllV2E0VVwvU1wvYldpais4VVRXWHZUSmxCV0xnPT0iLCJtYWMiOiIyNzRkODYzYzBhNTE4OTJlY2Q0MmY1OTczZTg5NGJkMWFiYzc5Yjc4NTNkNzk5NDVjODI4ODE0OTNkZWZiODhkIn0%3D; 29 | expires=Sat, 09-Dec-2017 22:14:11 GMT; Max-Age=7200; path=/'] 30 | Vary: [Accept-Encoding] 31 | X-RateLimit-Limit: ['25'] 32 | X-RateLimit-Remaining: ['7'] 33 | X-RateLimit-Reset: ['1512851037'] 34 | status: {code: 200, message: OK} 35 | version: 1 36 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_products_get_producer.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/products/9XVU7NK3PEGLAJ372X4F00000/producer?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7yTXUvDMBSG/8o412nT9HPN3RARxEu9C0ianM5ov5amqzj636VzTgSVgWy5S855 15 | n4eTkB1o6STwHTSyRuBwXaOVle6BwKA6BRyC47q5W91GX1sgUJnmBTg8Odf1XFBBx3H0lWwaWZje 16 | Ytda1/uqrQWVnRF0y/xA0M62elBoe0H/Ym/saeRPnHc4FRQPMwi6sZ5qNc7D2Oq/OCBgarnG0zj7 17 | 1n7PK02FgqaClkNVPaZFlqdxUpQyS2SSxloyvYxDnchSF+EywjIpsjwP/eduDQQsbg2O/fxEqh0a 18 | Bzw4470L+umbCOCrs1K5y7mPwlmuTVHhBd0H30TgI/Bt7jg7q/xonAgoi9KhXrlZr6VDZ/Y/MwxY 19 | 4gWRx9IFW3KW8DgHAnPxrW3mhof7qzk/dPr3PAu9IF4EAWcRD+Mf8tP0DgAA//8DACrA2CATBAAA 20 | headers: 21 | CF-RAY: [3caaa11c6ceb791e-LAX] 22 | Cache-Control: ['private, must-revalidate'] 23 | Connection: [keep-alive] 24 | Content-Encoding: [gzip] 25 | Content-Type: [application/json] 26 | Date: ['Sat, 09 Dec 2017 20:14:12 GMT'] 27 | ETag: [W/"1e67289d2d795dbd2759f218941e1833-gzip"] 28 | Server: [cloudflare-nginx] 29 | Set-Cookie: ['__cfduid=d7ec7153073e6ea61105e1607d1b1421e1512850451; expires=Sun, 30 | 09-Dec-18 20:14:11 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 31 | 'XSRF-TOKEN=eyJpdiI6IjRTSlB2SDdFWTVSeDBobDluUmlvakE9PSIsInZhbHVlIjoiWEZhaU5UaXkxUlFRRERUZTRNYVE3WWZ4YTlEYnloN1lvYkZcLzlMdWExYWF6N1c0M0xFRExxbmdrQW16cDhFMmFOTmkxUWFiYUtBR2ZBQlVUd1JEejRnPT0iLCJtYWMiOiI2MDE0MjhmMTE1YjllYTVjOTg5ZjgwNDMyZjFiMWEwMDNiZDI3NDJmZDI1NTcxNGU2ZWU4ODY2YmYwNzIwNzIzIn0%3D; 32 | expires=Sat, 09-Dec-2017 22:14:12 GMT; Max-Age=7200; path=/'] 33 | Vary: [Accept-Encoding] 34 | X-RateLimit-Limit: ['25'] 35 | X-RateLimit-Remaining: ['6'] 36 | X-RateLimit-Reset: ['1512851037'] 37 | status: {code: 200, message: OK} 38 | version: 1 39 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_products_get_review.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/products/0000000000C6FZLK664400000/reviews?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA9xUy47bMAz8lYJnb/SwvbJ1K/YXtqfVIqAtJlbXlgVZTpoG/vfCKZK2hwIB0lNv 15 | nBGHQ0ADnsFiQtBvZ+id/wANXUph0oYZdjweNy16j42bIoUxpmnTjoNhGJxhB7HhhkU6ODpOhhW2 16 | REuilA02edMIanlRCiqsrQuZK4UNbzjVFWQwx/4+n9twyUVpGM8NE+p+K8O+Nm0c2w9KCTKgOXRj 17 | dAjaz32fQRsJkzu4dLoyAZ3fRuod7a4UhkDJJdru0fmbEvvB+T1okJAB+m+Ofg2ZgmtvgDCm7oZ2 18 | cf7NbRrneK1tPG2HcU7dH8uR/ZxAn9cvouQGWg25KJ94/iTUJ861lLpYV1gfv49+bfjy+gJLBnOw 19 | D+iX7NE41LZ5VkrVVaFohxwrJetK7kqZW4VVI4SQ8hkL+w/icK+VYVNHfX/6T6OQ65w/EoW/6Jf3 20 | DAZaT8QZAu6dx+RGv6I0JuxBywzacfbpUgWK24B7Ai14Bu0cI/l0ZbKfkgucLnjN2AT67X1Zlh8A 21 | AAD//wMAUsMW4YoEAAA= 22 | headers: 23 | CF-RAY: [3caaa11f3ba120d8-LAX] 24 | Cache-Control: ['private, must-revalidate'] 25 | Connection: [keep-alive] 26 | Content-Encoding: [gzip] 27 | Content-Type: [application/json] 28 | Date: ['Sat, 09 Dec 2017 20:14:12 GMT'] 29 | ETag: [W/"07ce5f32087aa40cc4b1ded01db9d935-gzip"] 30 | Server: [cloudflare-nginx] 31 | Set-Cookie: ['__cfduid=d62cb420a7bc9b438cab5048e3a1294971512850452; expires=Sun, 32 | 09-Dec-18 20:14:12 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 33 | 'XSRF-TOKEN=eyJpdiI6IngyOFJOWVZialwvcTQ0RVRTQmlraGpRPT0iLCJ2YWx1ZSI6IkxIZXNId05URlJYeEwwSnFcL0EyM3ZhU1FGcXNjYzN1d3NNckxEU1lyU2w0d2NMd2hDT09MeGFrOHRkMTRYWW5DeXJ4bHBhUGhUaHp0XC9WK3FabE9qVVE9PSIsIm1hYyI6ImRiN2RiMTRhNjMwZTk4MmJmYjBmYWEzNzE3ZDRiMWQzMjljNjg2ZTM4NDQ2MWM0OWQ3YWI2NDg5MWRhODFjYWQifQ%3D%3D; 34 | expires=Sat, 09-Dec-2017 22:14:12 GMT; Max-Age=7200; path=/'] 35 | Vary: [Accept-Encoding] 36 | X-RateLimit-Limit: ['25'] 37 | X-RateLimit-Remaining: ['5'] 38 | X-RateLimit-Reset: ['1512851037'] 39 | status: {code: 200, message: OK} 40 | version: 1 41 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_products_get_strain.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/products/9XVU7NK3PEGLAJ372X4F00000/strain?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7RSTW/bMAz9KwHPtiU58Ud1a4OdCgw7tMOAaSgUiU20OJIryTG6wv99sJMA6VAM 15 | RT94oyi+98jHJ9AySuBPYOUOgcNyg94/zq5dIyGBTrUKOFz8+H5bfb2ef/tCnwck0Bi7BQ6bGNvA 16 | BRGk7/tMSWvlygSPrfMxZMrtBJGtEWTPMipIiF4aGwT5H/KDfx3uASw9vgnS2a11vU1XHlGjF0RN 17 | M6Vb10hBHnyqnMYs7NfjgL75eBJIwOzkGl+HPH0NZzupBbnvmuauliVVrNLl/IIVqtA5XVFZV4ui 18 | ZHSRl3UpK7qq8yL73Y6jBES9dLtW2sczP28POmdXB53/eEpfiDd7iqhTNQkweLL2RYIhgTVajEaF 19 | k9IA/F42AU/yjslByJQMU4bTWn/+SkBtTKM92hFBuc5G4OzTrnG090g3JOBxb7APZ8z0E5lPbEMC 20 | yqOMqC/jSK1lxGgmk3PKFiljKatmec7nC15UkMBY/OPsdAU3y7G/a/U7+ofhLwAAAP//AwBVE2+C 21 | LgQAAA== 22 | headers: 23 | CF-RAY: [3caaa122487f7936-LAX] 24 | Cache-Control: ['private, must-revalidate'] 25 | Connection: [keep-alive] 26 | Content-Encoding: [gzip] 27 | Content-Type: [application/json] 28 | Date: ['Sat, 09 Dec 2017 20:14:13 GMT'] 29 | ETag: [W/"49330abd036c376082e4786ef0c8dc6c-gzip"] 30 | Server: [cloudflare-nginx] 31 | Set-Cookie: ['__cfduid=d55267e1e14b999342e37b89d2e7d8d831512850452; expires=Sun, 32 | 09-Dec-18 20:14:12 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 33 | 'XSRF-TOKEN=eyJpdiI6ImpxZjlVXC93Ynd0TlFuS2dCZkdHYWtRPT0iLCJ2YWx1ZSI6Ikd2aVBSZ3VVN3pva3dDOGJ3NWJcL3p5eUV6NE9XN1ZDdUMzazVtUDZTenBqaWhTeGg5OUtmOFwvUTJscmU2YTc3YVhvajNxSjZMWVkyZHBRTW84ZkFicVE9PSIsIm1hYyI6ImEwODU3NGVhOTYxNTg2OTA3OTUzOTFhY2ViYzk5NDRkNzFlODdjZjlhOWNlMmU0Nzk5MzkyMjJiNGQ0ODdlZDIifQ%3D%3D; 34 | expires=Sat, 09-Dec-2017 22:14:12 GMT; Max-Age=7200; path=/'] 35 | Vary: [Accept-Encoding] 36 | X-RateLimit-Limit: ['25'] 37 | X-RateLimit-Remaining: ['4'] 38 | X-RateLimit-Reset: ['1512851037'] 39 | status: {code: 200, message: OK} 40 | version: 1 41 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_products_get_user.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/products/9XVU7NK3PEGLAJ372X4F00000/user?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA4yPQW6DMBBFr4JmDdggUtrZVVn0AEl33kzBTUYxxrKHoDTi7hWRGmXRSl3+xXt6 15 | /wo9CQFewXN38jRYQNgdrXMXyMGxPwHCUSQkNMqoeZ7LjrynD07RhjFKKrtxMIoCG3WuSm3UlGxM 16 | RqUfidDBsV+925XM3jg6yGGK7n/qEMdPdvbBmNx0AIT77qIlsf2rrD96Eit8+1Hrqin0U1FXWbXB 17 | WmP9svbwYL/GW9D7fgtLDlPo/+LbQreF3mS6weYZm/YXflm+AQAA//8DAAsT1ZNFAQAA 18 | headers: 19 | CF-RAY: [3caaa1252e48791e-LAX] 20 | Cache-Control: ['private, must-revalidate'] 21 | Connection: [keep-alive] 22 | Content-Encoding: [gzip] 23 | Content-Type: [application/json] 24 | Date: ['Sat, 09 Dec 2017 20:14:13 GMT'] 25 | ETag: [W/"6b664ee5d985f313972979078d27caf6-gzip"] 26 | Server: [cloudflare-nginx] 27 | Set-Cookie: ['__cfduid=d8f3d5490a77e26f70d7d0a1714a8e7741512850453; expires=Sun, 28 | 09-Dec-18 20:14:13 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 29 | 'XSRF-TOKEN=eyJpdiI6Ik8yeHZKR1pydEdPQ3NaaDIrTlR6RlE9PSIsInZhbHVlIjoiZ0xQUjdxb2NGUzR4d3VHWDZZWVpJcGpoWDc4Y2c4WSsrSUVmOE44TWlcL1dGMXB5RjNLb1dLV2Nia1J2NUtaR1wvRk5RZEUxc3Ywd0JjREpXb213WXl2UT09IiwibWFjIjoiMzAzNzZiNmEwZDIwODA5ZGQ5YmIxNzgyZGRhYTE5YjA1OGRiZjMwNGM0NmJlNTUxZWI5NzFkMTk3NTI1OTBjYyJ9; 30 | expires=Sat, 09-Dec-2017 22:14:13 GMT; Max-Age=7200; path=/'] 31 | Vary: [Accept-Encoding] 32 | X-RateLimit-Limit: ['25'] 33 | X-RateLimit-Remaining: ['3'] 34 | X-RateLimit-Reset: ['1512851037'] 35 | status: {code: 200, message: OK} 36 | version: 1 37 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_strains_get.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/strains/VUJCJ4TYMG000000000000000?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7ySa2/TMBSG/4p19mVISXPpevO3Kgi6ig6mtmNDkZATnzReUyez3Qur+t+RMzpK 15 | VdCEGP6WHJ/3Oa/fswXODAO6BckWCBSGLJ2TASpU4MAyrVKgcDMdRsOLyd3ovf/rAQcKIedAITem 16 | 0jT2Ym+9XjdSJiVLhFZYlcroRlouYo9VIvZWQcOPPW0UE1LH3p+UH9TLdJ/E3B//Yk+j1MLViFzH 17 | 3j1L525u7cTeg3LTkmNDr2bWmyr+qT44IBZshi8Tra/qg5dgsZcti+Irw26ImDWTJEw67d4FzzpZ 18 | N8mYz1kYshYPEz9rtru9xn1lXdgxonJRMfntIMSxHZGM7YhHKfonzl+niMjdtIYL3Id5ErBzYIYS 19 | jUj1fkoNFM6vSmVyVJJ8ELPcaHLWIhsyni/lnJwFb8iGDNgj/nRw/rQuo0/X4RGBbEhdu2t/mUZH 20 | NavTu72Zdj4Pr6O3/22DY+/Z8q6GYL0cW+hns5xJoQ2TQKH/DhyIyqJcJIIBhegjOHApef1xeQUO 21 | jHAj0hIojG7BgUnORMEkBwqTgVVOc1FwhdJKp+VSGqBBq/eKtp6BOwcUrgSu9SE7fEX0HmdtK2QG 22 | ed9YNmcGjahXP/T9rut33aBFgh4NfVpnbIuPpbQXppPI9i8r/pv+oOX6TTcISNikgU9bp/p3u+8A 23 | AAD//wMAaoUsZjkFAAA= 24 | headers: 25 | CF-RAY: [3caade4b1e925f69-LAS] 26 | Cache-Control: ['private, must-revalidate'] 27 | Connection: [keep-alive] 28 | Content-Encoding: [gzip] 29 | Content-Type: [application/json] 30 | Date: ['Sat, 09 Dec 2017 20:55:58 GMT'] 31 | ETag: [W/"485de6623b1d789a5e3b857a1ec58e0e-gzip"] 32 | Server: [cloudflare-nginx] 33 | Set-Cookie: ['__cfduid=dd4ac731464cd9c098a35b4f17d01c2311512852957; expires=Sun, 34 | 09-Dec-18 20:55:57 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 35 | 'XSRF-TOKEN=eyJpdiI6Iks3eGFcL2t3aGZvOWlzK0RoZ1VQcElnPT0iLCJ2YWx1ZSI6InVWcmZsMmpUeXgwMW1VS2dtNVBPMnVUMmFJVTExVktNRGN1Z3JtQ2M1QW4yY2VjVTVtS3ptY2ZKa0RNWjBrUEVUdWxBUjFoSTJiV0VJQkNuaDh5U2N3PT0iLCJtYWMiOiI3NTdlMDM1MWRhYjU1NjAwMmZkODI4Mjk1N2JlOWMwM2U0MTFjMzM0YmI3YzAzNTY3ZjRmNDQxZmI0NzA0MjQ0In0%3D; 36 | expires=Sat, 09-Dec-2017 22:55:58 GMT; Max-Age=7200; path=/'] 37 | Vary: [Accept-Encoding] 38 | X-RateLimit-Limit: ['25'] 39 | X-RateLimit-Remaining: ['21'] 40 | X-RateLimit-Reset: ['1512853750'] 41 | status: {code: 200, message: OK} 42 | version: 1 43 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_strains_get_available.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/strains/VUJCJ4TYMG000000000000000/availability/geo/37.7749295/-122.4194155/10?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA9yZXW/bNhSG/4rAi12ZFj9FicAwdNmSLliRAk03DNMQMDIjE5EpjaKTuoH/eyHJ 15 | cexEzmIvLhD7yjr24UtRD86X7sBIeQXk33fAqokGEpyq7Dp4r512YACmWZUBCf74fHp0ys7/+nCC 16 | 1j9gAApjr4EEY++rWqZhGt7e3g4zZa26NLXTVel8PczKSRqqyqThDR6iNKy9U8bWafjcyn5WNRvq 17 | /tsolZnyprRALjf76fj47ORk112MTF1pWytndJ2GmUrDWll45ZTNTJ2VaVhfXZV53iyvPJCAiqEQ 18 | WFCMG5PNgQQQEzJkOOIMJWA+AJUzmQbSToticXExVsXVRe7UZN3cWQDmw/ZmO6M2+diPgQRszfzv 19 | VDmvHZAgXrO3S5dT20gCLNDqb/dmShYumdPK69E735zfSHntTXuGBGEGEYcEBQRLkkgqmsM3E/21 20 | tM0fPp8fNbc2rUbP++MAMcmpRLzHfz54m4Sdj3Xwrir9WGfKmelkb6z5sYbqkdCSukgwnNBH1JE4 21 | wgnfjTrRSx3fQB3GaCN2vdAxhLaBDnNJyLbQcYgiiHCAhGRIcnZA0P1urrweBe+1Kvw4+CH4UxeF 22 | 1XW9N/iKVhCOW0F4uyK3RDAhiYiTxwhiwgh704EvgSQJCJE0lijeIfDd+zMmaXRADH7QI3PitLbB 23 | r18qt0/4Jnpk8kYJ6gelh9CHY8LIOnc0iXks8E7cJb3YUdSPHd8c+NaJXMLI/zvycYgEpDjAsaSJ 24 | xGiHyHfvzxpwD4i63/KvKvPFLGAE7Q04sxCBC5Ela7GIKcOPWYs4fdXajrNe1p6su0Bq1b5meklu 25 | JZIKyfm2hEUQEYiTACFJiUTogAjrYtrPahYclUWhM29u9N5I68LapZrBbE3snrgYEcTaenk1q9KY 26 | UCR2Qg69Wl23KavSF1V2AuKushOS4+2zKiaQogC17Qg6pKz66TjoAPxFF+ZGu9kee1fY0TdaUfrO 27 | 3EVoE3ebqzlCevMqFS/lDgeYSyYk5TtUc51/JBHtrwbfbDWnclsWRu2hlSjVdaHsKA0nC43e/iFG 28 | KCbtka4QR+IkpmK1hQVPA9LWHcQG6ATfrocl8Ut7WBwg3vSwON55cMIloZKSAyLu49RVhW56WOeD 29 | j8obbX1wpK1vd//a7FWtWtPAOg+rTg1mS7WHLjaKH89RiGAiId+jh02eybZxf7blWzDI2jkK/x/D 30 | O0IlO6Th3VmHR3DmcmVNto+gt/gCyxWJB9qSmEX8CW4M7Tosxv3N6wbethzabYEalTyRmO5Q2GFI 31 | ooBQSSKJ+ubM838GYKKbVxJ3oFK5sctn6kuvCiAxHoCsnFoPJEYDUGl3Ualcd1fZ1Dlt/b1l0Dm1 32 | lzWQpHv8dUuI/uL3wGUaqhtlCnVpCuNnaZjrMg3b9wYsIQlPw8ULg4RhztMQo5+avf1IwHw+n38D 33 | AAD//wMADWBCoY0ZAAA= 34 | headers: 35 | CF-RAY: [3ca2c3beee415f7b-LAS] 36 | Cache-Control: ['private, must-revalidate'] 37 | Connection: [keep-alive] 38 | Content-Encoding: [gzip] 39 | Content-Type: [application/json] 40 | Date: ['Fri, 08 Dec 2017 21:19:45 GMT'] 41 | ETag: [W/"74d0edc1275e5800658a7eba162da8ce-gzip"] 42 | Server: [cloudflare-nginx] 43 | Set-Cookie: ['__cfduid=d13215e513b9dbc540a0f2e070ed7a20f1512767984; expires=Sat, 44 | 08-Dec-18 21:19:44 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 45 | 'XSRF-TOKEN=eyJpdiI6ImVwWXFpZ3lHQzM5VnZpdDZtNWFIWEE9PSIsInZhbHVlIjoiaFVjY2hKUGJSTFZ5VDZXT1lmYldpN1Jra2t2UlFieXE4RGRnTmFId2VxbUgrRGxpMmdwOGhRelNVOVBtclZtK2VVejNQWlwvTmFkZHlpcDZRVTRYRURRPT0iLCJtYWMiOiI0ZTJmNDllYWI5YWU5NjMzZTU2Y2E4MjZiMDhmZDhiZmRiZmFlMzhjNjAxYzZhMGVjOTJkMjY5NWRmYzQ1Y2U5In0%3D; 46 | expires=Fri, 08-Dec-2017 23:19:44 GMT; Max-Age=7200; path=/'] 47 | Vary: [Accept-Encoding] 48 | X-RateLimit-Limit: ['25'] 49 | X-RateLimit-Remaining: ['21'] 50 | X-RateLimit-Reset: ['1512768492'] 51 | status: {code: 200, message: OK} 52 | - request: 53 | body: null 54 | headers: 55 | Accept: ['*/*'] 56 | Accept-Encoding: ['gzip, deflate'] 57 | Connection: [keep-alive] 58 | Cookie: [__cfduid=d13215e513b9dbc540a0f2e070ed7a20f1512767984; XSRF-TOKEN=eyJpdiI6ImVwWXFpZ3lHQzM5VnZpdDZtNWFIWEE9PSIsInZhbHVlIjoiaFVjY2hKUGJSTFZ5VDZXT1lmYldpN1Jra2t2UlFieXE4RGRnTmFId2VxbUgrRGxpMmdwOGhRelNVOVBtclZtK2VVejNQWlwvTmFkZHlpcDZRVTRYRURRPT0iLCJtYWMiOiI0ZTJmNDllYWI5YWU5NjMzZTU2Y2E4MjZiMDhmZDhiZmRiZmFlMzhjNjAxYzZhMGVjOTJkMjY5NWRmYzQ1Y2U5In0%3D] 59 | User-Agent: [python-requests/2.18.4] 60 | method: GET 61 | uri: https://www.cannabisreports.com/api/v1.0/strains/VUJCJ4TYMG000000000000000/availability/geo/37.7749295/-122.4194155/10?page=2 62 | response: 63 | body: 64 | string: !!binary | 65 | H4sIAAAAAAAAA7SSTYvbMBCG/0qYs219WMaJoJR2Dy2B0stuoVQlTGStI2JLriwnbIP/e7GdbrPQ 66 | 9lCobvNo5p3PC1QYEeSXCzhsDUjYoj6u3ptgAiQw6E6DhE8P27utuP/84R19+SCBxrojSDjE2PVS 67 | EUXO53Om0Tnc2z6YzofYZ9q3imBnFTmxjCrSx4DW9Yr8TTk+dVNBi++UyWuM1juQz8W+bdRA6aNu 68 | Vx/x2KCr/rWgyvadcT0Ga3pFNCriF0FF9s3Qpv6XPEaQkJfZmnEh2HpCrgYJKeM84yXdMA5jAl2w 69 | 2oB0Q9Ncjd0Bm8ddHbB9iRcCTGRz2ws0tj7EA0gQxS3+NmCIJoCE9fqWz9J+cFNKYCW9/fuJ8/yK 70 | dTAYTfUmTpOsMJpo52lyykRKi5SzFRUyp5IX0xpsa757Nzk83N9NrQ1d9af4IqUipZsVzyUXkrHf 71 | xI9fE2jNdHQX6LC27nmp0UdsQDKWgPaDiyBZAp0Juw5rA5LRBPQQgnHxSniyxMxmP9vT9vtZOpiT 72 | 9UP/H25TETyhbXBvGxufFKmNVyQvs7IUG74pFJlPQbCNYEWhCKOvp/peMRjHcfwBAAD//wMAU/6V 73 | fnIDAAA= 74 | headers: 75 | CF-RAY: [3ca2c3c29eca5f7b-LAS] 76 | Cache-Control: ['private, must-revalidate'] 77 | Connection: [keep-alive] 78 | Content-Encoding: [gzip] 79 | Content-Type: [application/json] 80 | Date: ['Fri, 08 Dec 2017 21:19:45 GMT'] 81 | ETag: [W/"467a64f01a252aaf2fa602e44ea3fbcd-gzip"] 82 | Server: [cloudflare-nginx] 83 | Set-Cookie: ['XSRF-TOKEN=eyJpdiI6ImUyMDdLS2NpSXZ2NjNvRE1cL1FGbjJnPT0iLCJ2YWx1ZSI6IjZZYk8rY0lGMVJyMEdJbW90MUo3Z3phODc2MVwvb0x0a0NEQ2VvWHBxSlJHZHFHaWdBZVpyM2NPQTFlUVU5aEQwMjhjUk1PVkNGQ0xCUm8rNFBqbDBPUT09IiwibWFjIjoiOGVlMDY2NmM5ZTJhYzllZmRiNzMwMGQxM2NiODg5OGQ2YmZlNzUwODkzMjRiODE2YjIzZmRmMjBkZmVjODE3ZCJ9; 84 | expires=Fri, 08-Dec-2017 23:19:45 GMT; Max-Age=7200; path=/'] 85 | Vary: [Accept-Encoding] 86 | X-RateLimit-Limit: ['25'] 87 | X-RateLimit-Remaining: ['20'] 88 | X-RateLimit-Reset: ['1512768492'] 89 | status: {code: 200, message: OK} 90 | version: 1 91 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_strains_get_effects_flavors.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/strains/VUJCJ4TYMG000000000000000/effectsFlavors?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAAzyP2w6CMBBE/2WeDSmWAunPmIqrbCKl6QUkxH83tOrryZmZ3R03Ew30DkpunD0b 15 | aHSV6qXECYMnE3nhuEGjr1ohxEHNc2L7gIaqOpWRTdPVUgg5LIpmnKPIkS4PwxYa7U+++e0yzSmO 16 | uaHv1AHvPpUZ+dOC42HLiurqBieQ8XHc8kR9zqEwJ58NWUrCShQLkPkBx5ag0fxvsi+m78w342lh 17 | WgN0fX6/PwAAAP//AwAjf4IfDwEAAA== 18 | headers: 19 | CF-RAY: [3caadcb4dcf15f57-LAS] 20 | Cache-Control: ['private, must-revalidate'] 21 | Connection: [keep-alive] 22 | Content-Encoding: [gzip] 23 | Content-Type: [application/json] 24 | Date: ['Sat, 09 Dec 2017 20:54:53 GMT'] 25 | ETag: [W/"32c5b45fe0f5ec052f337b81bfdc5957-gzip"] 26 | Server: [cloudflare-nginx] 27 | Set-Cookie: ['__cfduid=d9d1d0434b33af8a847900baca2e4cc3c1512852892; expires=Sun, 28 | 09-Dec-18 20:54:52 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 29 | 'XSRF-TOKEN=eyJpdiI6IjBJOXF6MXdSUGg4WlB6TG9NWkp6UlE9PSIsInZhbHVlIjoicHBPWUd2QkU4RUFVK25mMDVqbHFyb1AxWFkwQVFpOEYwTloxdGRTbEMwQmNCSk9qa3dHMGZMZDNURG1lb1hVbW5FTFUyZHZ1am05aEczZTBRdHFTTkE9PSIsIm1hYyI6ImFmMDRjYTJmY2I5N2Q0ZWY0ZDYwYTc1MzI5NjE3Zjk1ZTRjNzRkZDYzMTJmYzY4NTczOGYzMWYzYmU5ZWIyMTQifQ%3D%3D; 30 | expires=Sat, 09-Dec-2017 22:54:53 GMT; Max-Age=7200; path=/'] 31 | Vary: [Accept-Encoding] 32 | X-RateLimit-Limit: ['25'] 33 | X-RateLimit-Remaining: ['23'] 34 | X-RateLimit-Reset: ['1512853750'] 35 | status: {code: 200, message: OK} 36 | version: 1 37 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_strains_get_genetics.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/strains/CYGU94JYKY000000000000000/genetics?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA+yXX2/aMBTFv0rkZ5w4CWXEbyxr14e1k+g/pmUPxnHBanBS28A2xHefHAoDhqOq 15 | SqI9NI84vufc3HN/EiuQEk0A/r4CgswYwCDOs3w25kQ4X4hIJaEMdMCcFhRgEI3u7z7E3y6CLjp8 16 | QAdkXDwBDKZaFwonXuItl0uXEiHImCvJilxq5dJ8lnik4Im38F2UeEpLwoVKvKrKz/J1dTfF4Mtv 17 | iTcXTyJfCjiWjKVMJh7dtgazl9YS71lCmqfMVYuJ6VNmjWmBDuAzMmGvEyhfVXtfaFtGJd7jPMvg 18 | vwJuIUwPirE0zmcFEb8A3o31bmPQ+bgxeDRTdOJ580wZSyEtDXC2He1JgXUHTJhgmlO1daoABtvc 19 | qSOTwygOh60FL/F23talCCtnt9otiNmVr+aMTnmWSibMIc3nQgMcogZ97fTWHSDZgrOl2pMOGlTe 20 | qpmmJSOapQNtpFOimeZlzgKE+hD1oX/m+BEOEC5nZA5/56IM4m1s7s+L1HLf70LUg37f8fs4DDHq 21 | nri/7uyCfcV+cmqnVTAYRqNGQmOpXButZpvGWmDVsVLNpDou/86pOiNn5VS5GLnZkJGNUlGDrqop 22 | hRpUbp1S3QgHUTWlbqeE2xB1/XD++bKRvFgq14YoPSW8BT4dyNQMp4Pa72SqM2lWMpllMJ/c7MWl 23 | hU39sEFfbbDptHLLbIpwcIZRr5pNg8fJlAjuXOeu4/9NzKdu3IuvhucP93UnpqryW9mkCJUshWZ1 24 | VOKRTUtQ5NCvjUt2iZqZtF+6Ekk3pSPnxjg6GlyTPLIL/A88sqbLyqOXBVCaCLMOFxYkBahBa9VI 25 | 8htUbv9PXYDDU/fXP9Z/AAAA//8DAONPmI6PEgAA 26 | headers: 27 | CF-RAY: [3ca2efcc1b005f81-LAS] 28 | Cache-Control: ['private, must-revalidate'] 29 | Connection: [keep-alive] 30 | Content-Encoding: [gzip] 31 | Content-Type: [application/json] 32 | Date: ['Fri, 08 Dec 2017 21:49:49 GMT'] 33 | ETag: [W/"5df183ce86f3ed90f9881332e1e7a513-gzip"] 34 | Server: [cloudflare-nginx] 35 | Set-Cookie: ['__cfduid=d63f891ef0fbf62bcf9bfc403795d408d1512769788; expires=Sat, 36 | 08-Dec-18 21:49:48 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 37 | 'XSRF-TOKEN=eyJpdiI6IlI0M1ZGWUxRZFVMQ1M4UWtRWTBSbnc9PSIsInZhbHVlIjoiTmtWZGJoaDlkVmJ3MG12WXJKZ3lCUFRWeUtiZldLUUtPQVNtVW5WeDZXSE85V2tEa2FuYzBKOEJ2WmdRek5DRWM3NmdQbzFhc3Z2NFpJQzNDSDA0bmc9PSIsIm1hYyI6ImM1OGE5YmFiYTAxMDRlODg4YjBjNDE3NjVlZDY2OTQ5YTIyY2IxMjY4NjlhNzUwNmFiYzYwZWRlNmMxYzQxMTEifQ%3D%3D; 38 | expires=Fri, 08-Dec-2017 23:49:49 GMT; Max-Age=7200; path=/'] 39 | Vary: [Accept-Encoding] 40 | X-RateLimit-Limit: ['25'] 41 | X-RateLimit-Remaining: ['22'] 42 | X-RateLimit-Reset: ['1512770687'] 43 | status: {code: 200, message: OK} 44 | version: 1 45 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_strains_get_review.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/strains/VUJCJ4TYMG000000000000000/reviews?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7zZ227iSBAG4FdBfQ3jqu7q491qX2H3ajyK2n1IvAMGGTOZbJR3XxmSCcyGwdho 15 | LiLRxOWKwpfq351nFn3nmfv8zJZ185U59tB1m60ri7J4fHz8FHzT+Kretmmzbrvtp7BelYXf1GXx 16 | DT9BWbTpW50et2UhuIjkhVCUbeRofEKRNQpFFedWk+JGG66BzdmuXQ7r8+PmHBDKArEsQA1vVRbb 17 | 1fpr3az8yrM5S7vNw7qtPXNMszkLbfJd/a3unphrdsvlnG183dy1aVmn/PaW32xSV3fp7t7XDXOM 18 | +kK/XNXN/Y9Lmu916m/CBJuz7aYOT68dkm+7h7dFbnf7Voz3V6137WtBbJ/uVutd9/B2v/3PleIf 19 | HXPP/YeTunqV+jpAWCAuQM1QOiEd9bftv/nvuukv+PuvP9nLnO028Vw9LUAuUM0AnRSOmw/qX+ZT 20 | IaiAFrIMloCEsFJUkqpIGoJHkpSp4tKkHMZCoLIAXRYCh7cqi/BQN9t8igDhJwWs/4UMQKCOEexX 21 | 7wboyAAdG6BjA+bdgLnSAC1ALwTOUDnSDsYYuFQ/3YBGMFRRxlBpa3gEITl5rFREAdlyy7XnIONY 22 | A7IsoP/iw1uVRWrr8LVS9lSB+RnBnsVlBa8f1JlZcFi+Qjgs3iQcVm8UXi/cWzi8vgaD7P+ggc+4 23 | cCQd8msxDKi/wUCQiidLmATmCiSQtBkMKJOrkDIJKaIXmaopGNRhKAxtVRZ+mb4rZU4tqJEDwZwM 24 | BHN2IKjjgaDObAqcXW1ALUDPgByQIxhh4FL9dAMmxGAgGuIpKoEpeu1z9CRAUchSRU+a7Ph00Buw 25 | ZYFqeKuy6B58fKzDw20QnO4K/AQBP0JgjhGYYwT0jkBdj8D2OztqR8rJMQgu1U9HgMZnw7PKFVcE 26 | JvkMSeYg++mtiPsYEpCHPAFBHxGRD29VFr5ZN0+r9W57KRzcZF9gMCgfwPh8IPuMiHwG3AnupL5e 27 | wsX6G0iokiGfk6i0kCQMViASgqUqhBhiyil5a6vR+UAdtgRuhrc6K4FGPiv8BOF0IvwiHxyg3SYf 28 | qH62czPj4AQ6EtdiGFB/g3yAPmfIGFK2BpS1wWTlLdfWUxSCa2W0NHESBl0WaIe3Oovhf2lRTU8I 29 | wzaH94QwioFeoO2fGxEc0QgGl+qnM8hYkc5WVFynSiBPBiViEBZkjoFrI3yKWdMUBv08MMNbnWUw 30 | NiMcdpUfDvbLjyFwdm4iTMmKagFmgabPelJ9fABwCcKl+htASBFMrDxP1iIIRSSUlCRIKi99kChU 31 | 4KISEyD0MYHD8FbD58GosEgnDAz7DU+Oqt/mOcxAOSLH4XoJF+unS/BCILcVaZ1SsBVWWlci5yB4 32 | hCi15wSGuPRTJPCDhqGtfndgHHyQMOXpQS2QLxD7zCf1OAyX6qdjEJqizDFXQQAJGzNkLbjxpDPl 33 | WIFBFCGAHItBlwWIshAwvFVZ/LPzzW3Ok355qsiHjYR91cjnBr0AsRDQHwUhOLDXGhhQ//Jlzlap 34 | /2/DM9v4+7rxXb1u+lW37vySOeRzFta7pju83KT2buPvE3Mc5izs2jY13es7OD8U7Zfb/brntWXu 35 | 85eXl5f/AAAA//8DAC6tc9rXGAAA 36 | headers: 37 | CF-RAY: [3ca2ba2cbf385f8d-LAS] 38 | Cache-Control: ['private, must-revalidate'] 39 | Connection: [keep-alive] 40 | Content-Encoding: [gzip] 41 | Content-Type: [application/json] 42 | Date: ['Fri, 08 Dec 2017 21:13:12 GMT'] 43 | ETag: [W/"5c1fae3f13c19cb8d7d3ef19e52a8959-gzip"] 44 | Server: [cloudflare-nginx] 45 | Set-Cookie: ['__cfduid=da824bce9b76582bb947af5b8b831114e1512767592; expires=Sat, 46 | 08-Dec-18 21:13:12 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 47 | 'XSRF-TOKEN=eyJpdiI6IkNCVExSbk1xY0lybEJPQW1SWFNoZlE9PSIsInZhbHVlIjoiUExsTzUzaTZMbjBZT3lwb3lnQjJMXC8yRFBLcGlOM3ArWjFKRm9cL01hcmIyejkwVmo5Ukw0UitHdnJKVjB5Z1pFWnhHOVJRR2dmSk9sVklWODJLYk5zQT09IiwibWFjIjoiZmY1ZTE4MTliOWM2Yzc1MmZjZmQyMjA0MDdjYzA5ZDU3YWI3YzZiODNiMDlmZjMxNzJiYzI5ZWY2ZGQzZmY4OSJ9; 48 | expires=Fri, 08-Dec-2017 23:13:12 GMT; Max-Age=7200; path=/'] 49 | Vary: [Accept-Encoding] 50 | X-RateLimit-Limit: ['25'] 51 | X-RateLimit-Remaining: ['24'] 52 | X-RateLimit-Reset: ['1512768492'] 53 | status: {code: 200, message: OK} 54 | version: 1 55 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_strains_get_seed_company.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/strains/VUJCJ4TYMG000000000000000/seedCompany?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA7RTXY/aMBD8K2ieHZIAOYrfEFXLUUGRgLaqIlVLvAH3EicXG+gV8d8rhyL14Vqd 15 | VJ3fZj9mxuv1GYocQZ5hqGRIrNhY3VkxKwuBQ1ZnkPi0mU1m0TMHAoU2D5DYO1dbmYZpeDqduhkZ 16 | Q1ttG66rxtluVpVpSLVOw2PcjdLQMqsgq8qajGabhv8SeGxeRm9dQ9oEv2New1gdeCWbho9NkFWK 17 | u/a489dqiv/mhIAuaccvI2pLbRrWTZXrgtMwTsP8UBTf4iRXFA0p7ifJIMpixXeUb7f9N4py7sVx 18 | n+KYhjTofq9312lzK3rGON/tyWjryEBi/A4CEzKkCBKTsUdVUZVb3eKPEJgezI6aJ0hMNxC4N6rN 19 | 3S+uoDJsr4G3EJhRSTrzcDaHwJwKOmlIzD97xD90Vnn0BQILrsnPc7H0QO+4aWkW7yGwpIebw+WH 20 | FhsqfXbpHa6qg9t3xnlzVfrqY+s96YKMgsR6CoGN0Y5VZ+XIsYXEZoWLwPVhrJ9DVh2Mg7wbvPYu 21 | 3tbBegMNHzWf/jTQH76+gZvqRSBrmByrsfMWFDl2uv3AvSgeBNEgiEadaCR7I5kMIeCTPyvjCzbr 22 | ie8/1Opv/UkQJUFv1On1ZNSXyeCZ/svlFwAAAP//AwDH4BAkOgQAAA== 23 | headers: 24 | CF-RAY: [3ca2d5229ab75f5d-LAS] 25 | Cache-Control: ['private, must-revalidate'] 26 | Connection: [keep-alive] 27 | Content-Encoding: [gzip] 28 | Content-Type: [application/json] 29 | Date: ['Fri, 08 Dec 2017 21:31:37 GMT'] 30 | ETag: [W/"7f32dafc8179da1c68bb792d00752b6a-gzip"] 31 | Server: [cloudflare-nginx] 32 | Set-Cookie: ['__cfduid=d91596d9698c0cd376c7318c6ee045f211512768696; expires=Sat, 33 | 08-Dec-18 21:31:36 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 34 | 'XSRF-TOKEN=eyJpdiI6IkF0WlNuNmZnMEJEcHkyZFVUSVkrcFE9PSIsInZhbHVlIjoieVBKTUxQZnFoMkxcL3hkNFwvdFBFTWNlb2FyQ2lDU2s0VG11UEZOeU9NR1BhOSthU0M4NlVQNFl3MGVnaGV4Z0gyaU0raTJSWVBIbWs5Uk9wK0V0RkxYQT09IiwibWFjIjoiNWJjNjExMWY2NTcxNzg1NzEzNmVjOTVlMmI1NzExMWE0ZTg2NjgzM2RiY2UwYjhhMTY2ZjRhZTU4OTdmNTZjOCJ9; 35 | expires=Fri, 08-Dec-2017 23:31:37 GMT; Max-Age=7200; path=/'] 36 | Vary: [Accept-Encoding] 37 | X-RateLimit-Limit: ['25'] 38 | X-RateLimit-Remaining: ['22'] 39 | X-RateLimit-Reset: ['1512769412'] 40 | status: {code: 200, message: OK} 41 | version: 1 42 | -------------------------------------------------------------------------------- /cannabis_reports/tests/fixtures/cassettes/test_apis_strains_get_user.yml: -------------------------------------------------------------------------------- 1 | interactions: 2 | - request: 3 | body: null 4 | headers: 5 | Accept: ['*/*'] 6 | Accept-Encoding: ['gzip, deflate'] 7 | Connection: [keep-alive] 8 | User-Agent: [python-requests/2.18.4] 9 | method: GET 10 | uri: https://www.cannabisreports.com/api/v1.0/strains/VUJCJ4TYMG000000000000000/user?page=1 11 | response: 12 | body: 13 | string: !!binary | 14 | H4sIAAAAAAAAA4yPwWrDMBBEf0Xs2bZWJm2CbiW9F0p602Vrqc4SWRaSHEOD/73YpPTSQo9zmPdm 15 | bmCpEOgbBO4ugQYHGp7pyhYq8BwuoOFcSszaSCPneW46CoHeOScXx1Ry042DkRTZyKtq0Mgpu5SN 16 | tHdGod5zWKmnsxMviXsO5MXxThGvG8YlqGBK/n+2mMYP9u5Hkv3Ug4bv2CVHxdmnsv6yVFzh7VeL 17 | eKjxUKsHoR51ixpxXciD+xy3iW+nIywVTNH+0Vf7WmGNrVB7jTvd7n7pL8sXAAAA//8DAA0uh6VV 18 | AQAA 19 | headers: 20 | CF-RAY: [3ca249f72cf35f75-LAS] 21 | Cache-Control: ['private, must-revalidate'] 22 | Connection: [keep-alive] 23 | Content-Encoding: [gzip] 24 | Content-Type: [application/json] 25 | Date: ['Fri, 08 Dec 2017 19:56:36 GMT'] 26 | ETag: [W/"1d786a5fe8bbc19d18604dd2eb1845d7-gzip"] 27 | Server: [cloudflare-nginx] 28 | Set-Cookie: ['__cfduid=dfa6406ea2f10dff80208b937f86470a21512762996; expires=Sat, 29 | 08-Dec-18 19:56:36 GMT; path=/; domain=.cannabisreports.com; HttpOnly', 30 | 'XSRF-TOKEN=eyJpdiI6IjRnUWI2UXhpUXk2MURRNE1DZnppREE9PSIsInZhbHVlIjoieFJJSXFicktCdmdXb2RRNDlGQW1BNHFMZUxiNjVDT1I4emNmUzB4OXVRM3Qxcm5xdEVTUXpkOWU1Uktid1ZDWmRESGR6MFJNa0p0c05sUDQzYTJ3Vmc9PSIsIm1hYyI6ImVjMzMyZDQ4NmI1ZGU5ZTkzYWIxYzFmOWE3M2U2NzQxMTFmMDBmYTBmOWFkNDNmY2IyOGM1MzdmNjM4NzAwNzIifQ%3D%3D; 31 | expires=Fri, 08-Dec-2017 21:56:36 GMT; Max-Age=7200; path=/'] 32 | Vary: [Accept-Encoding] 33 | X-RateLimit-Limit: ['25'] 34 | X-RateLimit-Remaining: ['6'] 35 | X-RateLimit-Reset: ['1512763041'] 36 | status: {code: 200, message: OK} 37 | version: 1 38 | -------------------------------------------------------------------------------- /cannabis_reports/tests/test_apis_dispensaries.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .api_common import recorder 6 | from .api_entity import ApiEntityAbstract 7 | 8 | from ..models.dispensary import Dispensary 9 | 10 | 11 | class TestApisDispensaries(ApiEntityAbstract): 12 | """Tests the Dispensaries API endpoint.""" 13 | 14 | UID = 'ca/san-francisco/grass-roots' 15 | 16 | def setUp(self): 17 | super(TestApisDispensaries, self).setUp() 18 | self.endpoint = self.api.Dispensaries 19 | 20 | @recorder.use_cassette() 21 | def test_apis_dispensaries_list(self): 22 | """It should parse the response and return the proper object.""" 23 | self._test_apis_objects_list(Dispensary) 24 | 25 | @recorder.use_cassette() 26 | def test_apis_dispensaries_get(self): 27 | """It should not be implemented.""" 28 | self._test_apis_objects_get('Grass Roots') 29 | 30 | @recorder.use_cassette() 31 | def test_apis_dispensaries_get_extracts(self): 32 | """It should return the extracts for a dispensary.""" 33 | self._test_apis_objects_get_extracts() 34 | 35 | @recorder.use_cassette() 36 | def test_apis_dispensaries_get_strains(self): 37 | """It should return the strains for a dispensary.""" 38 | self._test_apis_objects_get_strains() 39 | 40 | @recorder.use_cassette() 41 | def test_apis_dispensaries_get_edibles(self): 42 | """It should return the edibles for a dispensary.""" 43 | self._test_apis_objects_get_edibles() 44 | 45 | @recorder.use_cassette() 46 | def test_apis_dispensaries_get_products(self): 47 | """It should return the products for a dispensary.""" 48 | self._test_apis_objects_get_products() 49 | 50 | @recorder.use_cassette() 51 | def test_apis_dispensaries_get_available(self): 52 | """It should not be implemented for this endpoint.""" 53 | with self.assertRaises(NotImplementedError): 54 | self._test_apis_objects_get_available() 55 | -------------------------------------------------------------------------------- /cannabis_reports/tests/test_apis_edibles.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .api_common import recorder 6 | from .api_product import ApiProductAbstract 7 | 8 | from ..models.edible import Edible 9 | 10 | 11 | class TestApisEdibles(ApiProductAbstract): 12 | """Tests the Edibles API endpoint.""" 13 | 14 | UID = '4KXM32V9YFC3G2EUNWP400000' 15 | 16 | def setUp(self): 17 | super(TestApisEdibles, self).setUp() 18 | self.endpoint = self.api.Edibles 19 | 20 | @recorder.use_cassette() 21 | def test_apis_edibles_list(self): 22 | """It should parse the response and return the proper object.""" 23 | self._test_apis_objects_list(Edible) 24 | 25 | @recorder.use_cassette() 26 | def test_apis_edibles_get(self): 27 | """It should return the proper singleton.""" 28 | self._test_apis_objects_get('Soda - Girl Scout Cookies and Cream') 29 | 30 | @recorder.use_cassette() 31 | def test_apis_edibles_get_user(self): 32 | """It should return the proper user singleton.""" 33 | self._test_apis_objects_get_user('Untamed Dame') 34 | 35 | @recorder.use_cassette() 36 | def test_apis_edibles_get_review(self): 37 | """It should return the reviews.""" 38 | self.UID = '0000000000L6M7ENLJVX00000' 39 | self._test_apis_objects_get_review() 40 | 41 | @recorder.use_cassette() 42 | def test_apis_edibles_get_effects_flavors(self): 43 | """It should return the effect & flavor profile.""" 44 | self.UID = '0000000000L6M7ENLJVX00000' 45 | self._test_apis_objects_get_effects_flavors() 46 | 47 | @recorder.use_cassette() 48 | def test_apis_edibles_get_available(self): 49 | """It should return the menu items.""" 50 | self.UID = '0000000000L6M7ENLJVX00000' 51 | self._test_apis_objects_get_available() 52 | 53 | @recorder.use_cassette() 54 | def test_apis_edibles_search(self): 55 | """It should parse the response and return the proper objects.""" 56 | self._test_apis_objects_search('chocolate', Edible) 57 | 58 | @recorder.use_cassette() 59 | def test_apis_edibles_get_producer(self): 60 | """It should return the producer.""" 61 | self._test_apis_objects_get_producer('Kushtown') 62 | 63 | @recorder.use_cassette() 64 | def test_apis_edibles_get_strain(self): 65 | """It should return the strain.""" 66 | self._test_apis_objects_get_strain('Girl Scout Cookies') 67 | -------------------------------------------------------------------------------- /cannabis_reports/tests/test_apis_extracts.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .api_common import recorder 6 | from .api_product import ApiProductAbstract 7 | 8 | from ..models.extract import Extract 9 | 10 | 11 | class TestApisExtracts(ApiProductAbstract): 12 | """Tests the Extracts API endpoint.""" 13 | 14 | UID = 'QLG39RN2AFPMR6WLTPLW00000' 15 | 16 | def setUp(self): 17 | super(TestApisExtracts, self).setUp() 18 | self.endpoint = self.api.Extracts 19 | 20 | @recorder.use_cassette() 21 | def test_apis_extracts_list(self): 22 | """It should parse the response and return the proper object.""" 23 | self._test_apis_objects_list(Extract) 24 | 25 | @recorder.use_cassette() 26 | def test_apis_extracts_get(self): 27 | """It should return the proper singleton.""" 28 | self._test_apis_objects_get('Blackwater OG - Honeycomb') 29 | 30 | @recorder.use_cassette() 31 | def test_apis_extracts_get_user(self): 32 | """It should return the proper user singleton.""" 33 | self._test_apis_objects_get_user('Untamed Dame') 34 | 35 | @recorder.use_cassette() 36 | def test_apis_extracts_get_review(self): 37 | """It should return the reviews.""" 38 | self.UID = '9XVU762EQ4VU7TG3N9NM00000' 39 | self._test_apis_objects_get_review() 40 | 41 | @recorder.use_cassette() 42 | def test_apis_extracts_get_effects_flavors(self): 43 | """It should return the effect & flavor profile.""" 44 | self.UID = '9XVU762EQ4VU7TG3N9NM00000' 45 | self._test_apis_objects_get_effects_flavors() 46 | 47 | @recorder.use_cassette() 48 | def test_apis_extracts_get_available(self): 49 | """It should return the menu items.""" 50 | self.UID = '9XVU7ZCENQVU7TGRFHPC00000' 51 | self._test_apis_objects_get_available() 52 | 53 | @recorder.use_cassette() 54 | def test_apis_extracts_search(self): 55 | """It should parse the response and return the proper objects.""" 56 | self._test_apis_objects_search('shatter', Extract) 57 | 58 | @recorder.use_cassette() 59 | def test_apis_extracts_get_producer(self): 60 | """It should return the producer.""" 61 | self._test_apis_objects_get_producer('Jnetics') 62 | 63 | @recorder.use_cassette() 64 | def test_apis_extracts_get_strain(self): 65 | """It should return the strain.""" 66 | self._test_apis_objects_get_strain('Blackwater OG') 67 | -------------------------------------------------------------------------------- /cannabis_reports/tests/test_apis_flowers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .api_common import recorder 6 | from .api_product import ApiProductAbstract 7 | 8 | from ..models.flower import Flower 9 | 10 | 11 | class TestApisFlowers(ApiProductAbstract): 12 | """Tests the Flowers API endpoint.""" 13 | 14 | UID = 'AHZ7H4N6467FVUDY3DAY00000' 15 | 16 | def setUp(self): 17 | super(TestApisFlowers, self).setUp() 18 | self.endpoint = self.api.Flowers 19 | 20 | @recorder.use_cassette() 21 | def test_apis_flowers_list(self): 22 | """It should parse the response and return the proper object.""" 23 | self._test_apis_objects_list(Flower) 24 | 25 | @recorder.use_cassette() 26 | def test_apis_flowers_get(self): 27 | """It should return the proper singleton.""" 28 | self._test_apis_objects_get('Ogre Berry - Flowers') 29 | 30 | @recorder.use_cassette() 31 | def test_apis_flowers_get_user(self): 32 | """It should return the proper user singleton.""" 33 | self._test_apis_objects_get_user('jbcrockett') 34 | 35 | @recorder.use_cassette() 36 | def test_apis_flowers_get_review(self): 37 | """It should return the reviews.""" 38 | self._test_apis_objects_get_review() 39 | 40 | @recorder.use_cassette() 41 | def test_apis_flowers_get_effects_flavors(self): 42 | """It should return the effect & flavor profile.""" 43 | self._test_apis_objects_get_effects_flavors() 44 | 45 | @recorder.use_cassette() 46 | def test_apis_flowers_get_available(self): 47 | """It should return the menu items.""" 48 | self.UID = 'YYRZDWGVU22WJVPGDJ7J00000' 49 | self._test_apis_objects_get_available() 50 | 51 | @recorder.use_cassette() 52 | def test_apis_flowers_search(self): 53 | """It should parse the response and return the proper objects.""" 54 | self._test_apis_objects_search('flowers', Flower) 55 | 56 | @recorder.use_cassette() 57 | def test_apis_flowers_get_producer(self): 58 | """It should return the producer.""" 59 | self._test_apis_objects_get_producer('HappyDay Farms') 60 | 61 | @recorder.use_cassette() 62 | def test_apis_flowers_get_strain(self): 63 | """It should return the strain.""" 64 | self._test_apis_objects_get_strain('Ogre Berry') 65 | -------------------------------------------------------------------------------- /cannabis_reports/tests/test_apis_producer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .api_common import recorder 6 | from .api_entity import ApiEntityAbstract 7 | 8 | from ..models.producer import Producer 9 | 10 | 11 | class TestApisProducers(ApiEntityAbstract): 12 | """Tests the Producers API endpoint.""" 13 | 14 | UID = '0000000000L6M7E0000000000' 15 | 16 | def setUp(self): 17 | super(TestApisProducers, self).setUp() 18 | self.endpoint = self.api.Producers 19 | 20 | @recorder.use_cassette() 21 | def test_apis_producers_list(self): 22 | """It should parse the response and return the proper object.""" 23 | self._test_apis_objects_list(Producer) 24 | 25 | @recorder.use_cassette() 26 | def test_apis_producers_get(self): 27 | """It should return the proper singleton.""" 28 | self._test_apis_objects_get('Kiva') 29 | 30 | @recorder.use_cassette() 31 | def test_apis_producers_get_extracts(self): 32 | """It should return the extracts for a producer.""" 33 | self.UID = '0000000000VU7TG0000000000' 34 | self._test_apis_objects_get_extracts() 35 | 36 | @recorder.use_cassette() 37 | def test_apis_producers_get_edibles(self): 38 | """It should return the edibles for a producer.""" 39 | self._test_apis_objects_get_edibles() 40 | 41 | @recorder.use_cassette() 42 | def test_apis_producers_get_products(self): 43 | """It should return the products for a producer.""" 44 | self.UID = '0000000000N4E9N0000000000' 45 | self._test_apis_objects_get_products() 46 | 47 | @recorder.use_cassette() 48 | def test_apis_producers_get_available(self): 49 | """It should return the availables for a producer.""" 50 | self._test_apis_objects_get_available() 51 | -------------------------------------------------------------------------------- /cannabis_reports/tests/test_apis_products.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .api_common import recorder 6 | from .api_product import ApiProductAbstract 7 | 8 | from ..models.product import Product 9 | 10 | 11 | class TestApisProducts(ApiProductAbstract): 12 | """Tests the Products API endpoint.""" 13 | 14 | UID = '9XVU7NK3PEGLAJ372X4F00000' 15 | 16 | def setUp(self): 17 | super(TestApisProducts, self).setUp() 18 | self.endpoint = self.api.Products 19 | 20 | @recorder.use_cassette() 21 | def test_apis_products_list(self): 22 | """It should parse the response and return the proper object.""" 23 | self._test_apis_objects_list(Product) 24 | 25 | @recorder.use_cassette() 26 | def test_apis_products_get(self): 27 | """It should return the proper singleton.""" 28 | self._test_apis_objects_get('Cherry Kola - Pre-roll') 29 | 30 | @recorder.use_cassette() 31 | def test_apis_products_get_user(self): 32 | """It should return the proper user singleton.""" 33 | self._test_apis_objects_get_user('Shelly') 34 | 35 | @recorder.use_cassette() 36 | def test_apis_products_get_review(self): 37 | """It should return the reviews.""" 38 | self.UID = '0000000000C6FZLK664400000' 39 | self._test_apis_objects_get_review() 40 | 41 | @recorder.use_cassette() 42 | def test_apis_products_get_effects_flavors(self): 43 | """It should return the effect & flavor profile.""" 44 | self.UID = '0000000000C6FZLK664400000' 45 | self._test_apis_objects_get_effects_flavors('numbness') 46 | 47 | @recorder.use_cassette() 48 | def test_apis_products_get_available(self): 49 | """It should return the menu items.""" 50 | self.UID = '0000000000C6FZLK664400000' 51 | self._test_apis_objects_get_available() 52 | 53 | @recorder.use_cassette() 54 | def test_apis_products_search(self): 55 | """It should parse the response and return the proper objects.""" 56 | self._test_apis_objects_search('pre-roll', Product) 57 | 58 | @recorder.use_cassette() 59 | def test_apis_products_get_producer(self): 60 | """It should return the producer.""" 61 | self._test_apis_objects_get_producer('Emeralds') 62 | 63 | @recorder.use_cassette() 64 | def test_apis_products_get_strain(self): 65 | """It should return the strain.""" 66 | self._test_apis_objects_get_strain('Cherry Kola') 67 | -------------------------------------------------------------------------------- /cannabis_reports/tests/test_apis_strains.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .api_common import recorder 6 | from .api_product import ApiProductAbstract 7 | 8 | from ..models.strain import Strain 9 | 10 | 11 | class TestApisStrains(ApiProductAbstract): 12 | """Tests the Strains API endpoint.""" 13 | 14 | UID = 'VUJCJ4TYMG000000000000000' 15 | 16 | def setUp(self): 17 | super(TestApisStrains, self).setUp() 18 | self.endpoint = self.api.Strains 19 | 20 | @recorder.use_cassette() 21 | def test_apis_strains_list(self): 22 | """It should parse the response and return the proper object.""" 23 | self._test_apis_objects_list(Strain) 24 | 25 | @recorder.use_cassette() 26 | def test_apis_strains_get(self): 27 | """It should return the proper singleton.""" 28 | self._test_apis_objects_get('Jack Herer') 29 | 30 | @recorder.use_cassette() 31 | def test_apis_strains_get_user(self): 32 | """It should return the proper user singleton.""" 33 | self._test_apis_objects_get_user('David') 34 | 35 | @recorder.use_cassette() 36 | def test_apis_strains_get_review(self): 37 | """It should return the reviews.""" 38 | self._test_apis_objects_get_review() 39 | 40 | @recorder.use_cassette() 41 | def test_apis_strains_get_effects_flavors(self): 42 | """It should return the effect & flavor profile.""" 43 | self._test_apis_objects_get_effects_flavors() 44 | 45 | @recorder.use_cassette() 46 | def test_apis_strains_get_available(self): 47 | """It should return the menu items.""" 48 | self._test_apis_objects_get_available() 49 | 50 | @recorder.use_cassette() 51 | def test_apis_strains_search(self): 52 | """It should parse the response and return the proper objects.""" 53 | self._test_apis_objects_search('Blue', Strain) 54 | 55 | @recorder.use_cassette() 56 | def test_apis_strains_get_seed_company(self): 57 | """It should return the seed company.""" 58 | seed_company = self.api.Strains.get_seed_company( 59 | 'VUJCJ4TYMG000000000000000', 60 | ) 61 | self.assertEqual(seed_company.name, 'Sensi Seeds') 62 | 63 | @recorder.use_cassette() 64 | def test_apis_strains_get_genetics(self): 65 | """It should return the parent strains.""" 66 | genetics = self.api.Strains.get_genetics('CYGU94JYKY000000000000000') 67 | found_parent = False 68 | for genetic in genetics: 69 | self.assertIsInstance(genetic, Strain) 70 | if genetic.name == 'Afghani No. 1': 71 | found_parent = True 72 | self.assertTrue(found_parent) 73 | 74 | @recorder.use_cassette() 75 | def test_apis_strains_get_children(self): 76 | """It should return the child strains.""" 77 | children = self.api.Strains.get_children('VUJCJ4TYMG000000000000000', 78 | limit=self.LIMIT_PAGE) 79 | found_child = False 80 | for child in children: 81 | self.assertIsInstance(child, Strain) 82 | if child.name == 'Jack Flash': 83 | found_child = True 84 | self.assertTrue(found_child) 85 | -------------------------------------------------------------------------------- /cannabis_reports/tests/test_base_api.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import mock 6 | import unittest 7 | 8 | from .. import BaseApi 9 | from .. import BaseModel 10 | from ..request_paginator import RequestPaginator 11 | 12 | 13 | PAGINATOR = 'cannabis_reports.base_api.RequestPaginator' 14 | 15 | 16 | class TestApi(BaseApi): 17 | __object__ = BaseModel 18 | 19 | 20 | class TestBaseApi(unittest.TestCase): 21 | 22 | ENDPOINT = '/endpoint' 23 | DATA = {'test': 1234} 24 | REQUEST_TYPE = RequestPaginator.POST 25 | 26 | def new_api(self, endpoint=ENDPOINT, data=DATA, request_type=REQUEST_TYPE, 27 | singleton=False, session=None, out_type=None): 28 | return TestApi( 29 | endpoint, data, request_type, singleton, session, out_type, 30 | ) 31 | 32 | def test_new(self): 33 | """It should return a new TestApi instance.""" 34 | self.assertIsInstance(self.new_api(), TestApi) 35 | 36 | def test_new_paginator(self): 37 | """It should return a new API object with a paginator.""" 38 | self.assertIsInstance(self.new_api().paginator, RequestPaginator) 39 | 40 | def test_new_paginator_create(self): 41 | """It should create the paginator with the proper args.""" 42 | session = 'session' 43 | with mock.patch.object(RequestPaginator, '__init__') as init: 44 | init.return_value = None 45 | self.new_api(session=session) 46 | init.assert_called_once_with( 47 | endpoint='https://www.cannabisreports.com/api/' 48 | 'v1.0%s' % self.ENDPOINT, 49 | data=self.DATA, 50 | output_type=TestApi.__object__.from_api, 51 | request_type=self.REQUEST_TYPE, 52 | session=session, 53 | iteration_limit=None, 54 | ) 55 | 56 | @mock.patch(PAGINATOR) 57 | def test_new_paginator_singleton(self, paginator): 58 | """It should return the record if singleton and found.""" 59 | paginator().call.return_value = {'ucpc': '9876'} 60 | res = self.new_api(singleton=True) 61 | self.assertIsInstance(res, BaseModel) 62 | self.assertEqual(res.ucpc, '9876') 63 | 64 | @mock.patch(PAGINATOR) 65 | def test_new_paginator_singleton_none(self, paginator): 66 | """It should return None if singleton and not found.""" 67 | paginator().call.return_value = {} 68 | res = self.new_api(singleton=True) 69 | self.assertIs(res, None) 70 | 71 | @mock.patch(PAGINATOR) 72 | def test_base_api_iterates_paginator(self, paginator): 73 | """It should pass iteration to the paginator.""" 74 | expect = [BaseModel(ucpc='1'), BaseModel(ucpc='2')] 75 | paginator().call.return_value = expect 76 | for idx, value in enumerate(self.new_api()): 77 | self.assertEqual(value, expect[idx]) 78 | 79 | @mock.patch(PAGINATOR) 80 | def test_new_paginator_singleton_out_type(self, paginator): 81 | """It should return an object of the correct type if defined.""" 82 | paginator().call.return_value = {'ucpc': '9876'} 83 | res = self.new_api(singleton=True, out_type=mock.MagicMock()) 84 | self.assertIsInstance(res, mock.MagicMock) 85 | 86 | def test_new_object(self): 87 | """It should return the proper object.""" 88 | expect = '123' 89 | res = BaseApi.new_object({'ucpc': expect}) 90 | self.assertIsInstance(res, BaseModel) 91 | self.assertEqual(res.ucpc, expect) 92 | -------------------------------------------------------------------------------- /cannabis_reports/tests/test_base_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import properties 6 | import unittest 7 | 8 | from six import string_types 9 | 10 | from .. import BaseModel 11 | from ..exceptions import CannabisReportsValidationException 12 | 13 | 14 | class TestModel(BaseModel): 15 | a_key = properties.String('A key') 16 | sub_instance = properties.Instance( 17 | 'Sub Instance', instance_class=BaseModel, 18 | ) 19 | list = properties.List( 20 | 'List', prop=properties.Instance('List Instance', 21 | instance_class=BaseModel), 22 | ) 23 | list_string = properties.List( 24 | 'List of Strings', prop=properties.String('String'), 25 | ) 26 | not_a_field = True 27 | 28 | 29 | class TestBaseModel(unittest.TestCase): 30 | 31 | def setUp(self): 32 | super(TestBaseModel, self).setUp() 33 | self.test_values = { 34 | 'aKey': 'value', 35 | 'subInstance': { 36 | 'ucpc': '1234', 37 | }, 38 | 'list': [ 39 | {'ucpc': '4321'}, 40 | ], 41 | } 42 | self.internal_values = { 43 | 'a_key': self.test_values['aKey'], 44 | 'sub_instance': self.test_values['subInstance'], 45 | 'list': self.test_values['list'], 46 | } 47 | 48 | def new_record(self): 49 | return TestModel.from_api(**self.test_values) 50 | 51 | def test_from_api_new_instance(self): 52 | """It should return a new instance of the class.""" 53 | self.assertIsInstance(self.new_record(), TestModel) 54 | 55 | def test_from_api_camel_to_snake(self): 56 | """It should call the init with snake cased keys.""" 57 | self.assertEqual(self.new_record().a_key, self.test_values['aKey']) 58 | 59 | def test_from_api_sub_instance(self): 60 | """It should properly instantiate sub-instances.""" 61 | self.assertIsInstance(self.new_record().sub_instance, BaseModel) 62 | 63 | def test_from_api_list(self): 64 | """It should properly convert lists of instances.""" 65 | res = self.new_record() 66 | self.assertIsInstance(res.list, list) 67 | self.assertIsInstance(res.list[0], BaseModel) 68 | 69 | def test_from_api_invalid_attribute(self): 70 | """It should remove any invalid attributes.""" 71 | record = TestModel.from_api(**{'no_exist': 'value'}) 72 | with self.assertRaises(AttributeError): 73 | record.no_exist 74 | 75 | def test_to_api_camel_case(self): 76 | """It should properly camel case the API args.""" 77 | res = self.new_record().to_api() 78 | self.assertEqual(res['aKey'], self.internal_values['a_key']) 79 | 80 | def test_to_api_instance(self): 81 | """It should properly convert sub-instances to dict.""" 82 | res = self.new_record().to_api() 83 | self.assertIsInstance(res['subInstance'], dict) 84 | 85 | def test_to_api_list(self): 86 | """It should properly convert sub-instances within lists props.""" 87 | res = self.new_record().to_api() 88 | self.assertIsInstance(res['list'], list) 89 | self.assertIsInstance(res['list'][0], dict) 90 | 91 | def test_to_api_list_string(self): 92 | """It should properly handle naive lists.""" 93 | expect = ['1', '2'] 94 | self.test_values['list_string'] = expect 95 | res = self.new_record().to_api() 96 | self.assertIsInstance(res['listString'], list) 97 | self.assertIsInstance(res['listString'][0], string_types) 98 | 99 | def test_get_non_empty_vals(self): 100 | """It should return the dict without None and False.""" 101 | expect = { 102 | 'good_int': 1234, 103 | 'bad_false': False, 104 | 'good_true': True, 105 | 'bad_none': None, 106 | } 107 | res = BaseModel.get_non_empty_vals(expect) 108 | del expect['bad_none'], expect['bad_false'] 109 | self.assertDictEqual(res, expect) 110 | 111 | def test_parse_property_invalid_property(self): 112 | """It should raise an exception if property name is invalid.""" 113 | with self.assertRaises(CannabisReportsValidationException): 114 | BaseModel._parse_property('no exist', 'value') 115 | 116 | def test_dict_lookup_exist(self): 117 | """It should return the attribute value when it exists.""" 118 | self.assertEqual( 119 | self.new_record()['a_key'], self.internal_values['a_key'], 120 | ) 121 | 122 | def test_dict_lookup_no_exist(self): 123 | """It should raise a KeyError when the attribute isn't a field.""" 124 | with self.assertRaises(KeyError): 125 | self.new_record()['not_a_field'] 126 | 127 | def test_dict_set_exist(self): 128 | """It should set the attribute via the items.""" 129 | expect = 'Test-Expect' 130 | record = self.new_record() 131 | record['a_key'] = expect 132 | self.assertEqual(record.a_key, expect) 133 | 134 | def test_dict_set_no_exist(self): 135 | """It should raise a KeyError and not change the non-field.""" 136 | record = self.new_record() 137 | with self.assertRaises(KeyError): 138 | record['not_a_field'] = False 139 | self.assertTrue(record.not_a_field) 140 | 141 | def test_get_exist(self): 142 | """It should return the attribute if it exists.""" 143 | self.assertEqual( 144 | self.new_record().get('a_key'), self.internal_values['a_key'], 145 | ) 146 | 147 | def test_get_no_exist(self): 148 | """It should return the default if the attribute doesn't exist.""" 149 | expect = 'Test' 150 | self.assertEqual( 151 | self.new_record().get('not_a_field', expect), expect, 152 | ) 153 | 154 | def test_from_api_list_no_model(self): 155 | """Test ``from_api`` when there is a list of non-property objects.""" 156 | self.test_values['list_string'] = [ 157 | 'test', 'again', 158 | ] 159 | self.assertEqual(self.new_record().list_string, 160 | self.test_values['list_string']) 161 | -------------------------------------------------------------------------------- /cannabis_reports/tests/test_cannabis_reports.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import unittest 6 | 7 | from .. import AuthProxy 8 | from .. import CannabisReports 9 | from ..apis import __all__ as all_apis 10 | 11 | 12 | class TestCannabisReports(unittest.TestCase): 13 | 14 | API_KEY = 'test key' 15 | 16 | def setUp(self): 17 | super(TestCannabisReports, self).setUp() 18 | self.hs = CannabisReports(self.API_KEY) 19 | 20 | def test_init_session(self): 21 | """It should build a session with the proper authentication.""" 22 | self.assertEqual( 23 | self.hs.session.headers['X-API-Key'], self.API_KEY, 24 | ) 25 | 26 | def test_load_apis(self): 27 | """It should load all available APIs.""" 28 | self.assertEqual(len(self.hs.__apis__), len(all_apis)) 29 | 30 | def test_api_instance_attributes(self): 31 | """It should properly set all of the API instance attributes.""" 32 | for api_name, api in self.hs.__apis__.items(): 33 | self.assertEqual(getattr(self.hs, api_name), api) 34 | 35 | def test_api_auth_proxy(self): 36 | """It should wrap the APIs in an AuthProxy.""" 37 | for api in self.hs.__apis__.values(): 38 | self.assertIsInstance(api, AuthProxy) 39 | -------------------------------------------------------------------------------- /cannabis_reports/tests/test_exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import unittest 6 | 7 | from ..exceptions import (CannabisReportsRemoteException, 8 | CannabisReportsValidationException, 9 | ) 10 | 11 | 12 | class TestExceptions(unittest.TestCase): 13 | 14 | def test_cannabis_reports_remote_exception(self): 15 | """It should have the proper str representation.""" 16 | code = 404 17 | message = 'A Fail' 18 | e = CannabisReportsRemoteException(code, message) 19 | self.assertEqual(str(e), '(404) A Fail') 20 | 21 | def test_cannabis_reports_base_exception(self): 22 | """It should include the message in string.""" 23 | message = 'message' 24 | e = CannabisReportsValidationException(message) 25 | self.assertEqual(str(e), message) 26 | -------------------------------------------------------------------------------- /cannabis_reports/tests/test_request_paginator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import mock 6 | import unittest 7 | 8 | from contextlib import contextmanager 9 | 10 | from ..request_paginator import RequestPaginator 11 | 12 | 13 | class TestRequestPaginator(unittest.TestCase): 14 | 15 | REQUEST_TYPES = ['get', 'delete', 'post', 'put'] 16 | 17 | def setUp(self): 18 | self.vals = { 19 | 'endpoint': 'endpoint', 20 | 'data': {'param': 1}, 21 | 'output_type': dict, 22 | } 23 | self.test_responses = [ 24 | { 25 | 'meta': { 26 | 'pagination': { 27 | 'current_page': 1, 28 | 'total_pages': 3, 29 | }, 30 | }, 31 | 'data': [{ 32 | 'page': 1, 33 | }], 34 | }, 35 | { 36 | 'meta': { 37 | 'pagination': { 38 | 'current_page': 2, 39 | 'total_pages': 3, 40 | }, 41 | }, 42 | 'data': [{ 43 | 'page': 2, 44 | }], 45 | }, 46 | { 47 | 'meta': { 48 | 'pagination': { 49 | 'current_page': 3, 50 | 'total_pages': 3, 51 | }, 52 | }, 53 | 'data': [{ 54 | 'page': 3, 55 | }], 56 | }, 57 | ] 58 | self.paginator = RequestPaginator(**self.vals) 59 | 60 | @contextmanager 61 | def mock_session(self, response_code=200, responses=None, 62 | mock_attrs=None): 63 | if responses is None: 64 | responses = self.test_responses 65 | if mock_attrs is None: 66 | mock_attrs = ['get', 'delete', 'post', 'put'] 67 | elif isinstance(mock_attrs, str): 68 | mock_attrs = [mock_attrs] 69 | with mock.patch.object(self.paginator, 'session') as session: 70 | response = mock.MagicMock() 71 | response.status_code = response_code 72 | response.json.side_effect = responses 73 | for attr in mock_attrs: 74 | method = getattr(session, attr) 75 | method.return_value = response 76 | yield session 77 | 78 | def do_call(self, request_type='get'): 79 | self.params = {'param_test': 23234} 80 | with self.mock_session(mock_attrs=request_type) as session: 81 | return session, getattr(self.paginator, request_type)(self.params) 82 | 83 | def _test_result(self, res): 84 | self.assertEqual(len(res), 1) 85 | self.assertDictEqual(res[0], self.test_responses[0]['data'][0]) 86 | 87 | def _test_session_call_json(self, session, request_type): 88 | method = getattr(session, request_type) 89 | method.assert_called_once_with( 90 | url=self.vals['endpoint'], 91 | json=self.params, 92 | verify=True, 93 | ) 94 | 95 | def test_init_attrs(self): 96 | """ It should correctly assign instance attributes. """ 97 | attrs = { 98 | attr: getattr(self.paginator, attr) for attr in self.vals.keys() 99 | } 100 | self.assertDictEqual(attrs, self.vals) 101 | 102 | @mock.patch('cannabis_reports.request_paginator.requests') 103 | def test_init_session(self, requests): 104 | """ It should initialize a requests session. """ 105 | paginator = RequestPaginator(**self.vals) 106 | self.assertEqual(paginator.session, requests.Session()) 107 | 108 | def test_get_gets(self): 109 | """ It should call the session with proper args. """ 110 | session, _ = self.do_call() 111 | session.get.assert_called_once_with( 112 | url=self.vals['endpoint'], 113 | params=self.params, 114 | verify=True, 115 | ) 116 | 117 | def test_returns(self): 118 | """The returns should all return properly.""" 119 | for request_type in self.REQUEST_TYPES: 120 | _, res = self.do_call(request_type) 121 | self._test_result(res) 122 | 123 | def test_session_calls(self): 124 | """The calls should all be handled properly (tests all but GET).""" 125 | self.REQUEST_TYPES.remove('get') 126 | for request_type in self.REQUEST_TYPES: 127 | session, _ = self.do_call(request_type) 128 | self._test_session_call_json(session, request_type) 129 | 130 | def test_call_get(self): 131 | """It should get when the request type is GET.""" 132 | params = {'param_test': 23234} 133 | self.paginator.request_type = self.paginator.GET 134 | with mock.patch.object(self.paginator, 'get') as get: 135 | self.paginator.call(params) 136 | get.assert_called_once_with(params) 137 | 138 | def test_call_post(self): 139 | """It should post when the request type is POST.""" 140 | params = {'param_test': 23234} 141 | self.paginator.request_type = self.paginator.POST 142 | with mock.patch.object(self.paginator, 'post') as post: 143 | self.paginator.call(params) 144 | post.assert_called_once_with(params) 145 | 146 | def test_iter(self): 147 | """ It should iterate until the end & yield data. """ 148 | with self.mock_session() as session: 149 | session.get().json.side_effect = self.test_responses 150 | res = list(self.paginator) 151 | expect = [{'page': 1}, {'page': 2}, {'page': 3}] 152 | self.assertEqual(res, expect) 153 | 154 | def test_iter_limit(self): 155 | """ It should stop iteration after the correct page. """ 156 | with self.mock_session() as session: 157 | session.get().json.side_effect = self.test_responses 158 | self.paginator.limit_iter = 2 159 | res = list(self.paginator) 160 | expect = [{'page': 1}, {'page': 2}] 161 | self.assertEqual(res, expect) 162 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2016-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from setuptools import Command, setup 6 | from setuptools import find_packages 7 | from unittest import TestLoader, TextTestRunner 8 | 9 | from os import path 10 | 11 | 12 | PROJECT = 'cannabis-reports' 13 | SHORT_DESC = 'This library allows you to interact with Cannabis Reports ' \ 14 | 'using Python.' 15 | README_FILE = 'README.rst' 16 | 17 | CLASSIFIERS = [ 18 | 'Development Status :: 4 - Beta', 19 | 'Environment :: Console', 20 | 'Intended Audience :: Developers', 21 | 'License :: OSI Approved :: MIT License', 22 | 'Programming Language :: Python', 23 | 'Programming Language :: Python :: 2', 24 | 'Programming Language :: Python :: 2.7', 25 | 'Programming Language :: Python :: 3', 26 | 'Programming Language :: Python :: 3.4', 27 | 'Programming Language :: Python :: 3.5', 28 | 'Programming Language :: Python :: 3.6', 29 | 'Programming Language :: Python :: 3.7', 30 | 'Topic :: Software Development :: Libraries :: Python Modules', 31 | ] 32 | 33 | 34 | setup_vals = { 35 | 'name': PROJECT, 36 | 'author': 'LasLabs Inc.', 37 | 'author_email': 'support@laslabs.com', 38 | 'description': SHORT_DESC, 39 | 'url': 'https://laslabs.github.io/python-%s' % PROJECT, 40 | 'download_url': 'https://github.com/LasLabs/python-%s' % PROJECT, 41 | 'license': 'MIT', 42 | 'classifiers': CLASSIFIERS, 43 | } 44 | 45 | 46 | if path.exists(README_FILE): 47 | with open(README_FILE) as fh: 48 | setup_vals['long_description'] = fh.read() 49 | 50 | 51 | class FailTestException(Exception): 52 | """ It provides a failing build """ 53 | pass 54 | 55 | 56 | class Tests(Command): 57 | """ Run test & coverage, save reports as XML """ 58 | 59 | user_options = [] # < For Command API compatibility 60 | 61 | def initialize_options(self, ): 62 | pass 63 | 64 | def finalize_options(self, ): 65 | pass 66 | 67 | def run(self, ): 68 | loader = TestLoader() 69 | tests = loader.discover('.', 'test_*.py') 70 | t = TextTestRunner(verbosity=1) 71 | res = t.run(tests) 72 | if not res.wasSuccessful(): 73 | raise FailTestException() 74 | 75 | 76 | if __name__ == "__main__": 77 | setup( 78 | packages=find_packages(exclude='tests'), 79 | use_scm_version=True, 80 | cmdclass={'test': Tests}, 81 | install_requires=[ 82 | 'properties', 83 | 'pytz', 84 | 'requests', 85 | ], 86 | setup_requires=[ 87 | 'setuptools_scm', 88 | ], 89 | tests_require=[ 90 | 'mock', 91 | 'vcrpy', 92 | ], 93 | **setup_vals 94 | ) 95 | -------------------------------------------------------------------------------- /test_requirements.txt: -------------------------------------------------------------------------------- 1 | mock 2 | vcrpy 3 | --------------------------------------------------------------------------------