{ "info": { "author": "Steve Beaumont", "author_email": "steve@hi2.me.uk", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "# Bebanjo API client\n\nA client library interfacing to Bebanjo's Movida and Sequence APIs allowing integration developers to focus on the business logic of their application and not the low level detail.\n\nThe library provides support for authentication, exception handling, logging and utilities for common tasks. It can be used in an interactive session. By design it is very loosely coupled to Movida/Sequence schemas.\n\n## Example Application\n\nTo demonstrate some features, here is an application to upload an image on all titles scheduled on platform `Android GB` and target them for that platform and set them as the `post art` for that title in the Movida UI.\n\n\n``` python\nfrom bebanjo import MovidaAPI\n\nmapi = MovidaAPI(env='staging')\n\nIMAGE_URL = 'tests/image/1yeVJox3rjo2jBKrrihIMj7uoS9.JPEG'\n\nplatforms = mapi.platforms.fetch()\ntarget_platform = filter(lambda p: p.name == 'Android GB', platforms)[0]\nfor title in target_platform.titles.get_paginated():\n image = title.images.create_image(IMAGE_URL, meta1={'IsPosterArt': True})\n image.target_platforms.create(target_platform.url)\n```\n\n> Although this would work as described, a well designed application would also include exception handling, checking if the image already exists and logging to file.\n\n## Installation\n\n### PyPI\n\n``` bash\npip install --user bebanjo-api\n```\n\n### GIT\n\nVisit [bebanjo-api](https://gitlab.com/hi2meuk/bebanjo-api) in **GitLab** to clone and contribute to the project.\n\n## Using the Bebanjo client library\n\n### Setting up your application\n\n``` python\nfrom bebanjo import MovidaAPI, install_auth_handlers\n```\n\n#### Robot account credentials\n\nThe authentication handler must be initialised with login data for the Bebanjo environments used. The library assumes there no distinction between Sequence and Movida credentials. The format of the credentials to be supplied to the handler initialisation is a nested dict as follows:\n\n``` python\nconfig = {\n 'staging': {\n 'name': 'robot_hi2meuk',\n 'password': 'mypassword'\n }\n}\n```\n\n> The environment key(s) must be one of: `staging`, `preproduction` or `production`.\n\nSetup the authentication handler before instantiating an API providing a config data structure as previously described:\n\n``` python\ninstall_auth_handlers(config)\n```\n\nA function is provided by the library to setup the auth config based on a local JSON file.\n\n``` python\nfrom bebanjo.utils import read_local_config\nconfig = read_local_config(CONFIG_FILE)\n```\n\n> The config file must be in JSON format. If a file path is not supplied, the default is \".bebanjo.json\" in users home directory (Windows or Linux).\n\n#### Create a Movida API instance for your chosen environment\n\n``` python\nmapi = MovidaAPI(env='staging')\n```\n\nIt is possible to specify a local Wiremock server to emulate Movida/Sequence for component testing purposes:\n\n``` python\nmock_url = 'http://localhost:8080/api'\nmapi = MovidaAPI(url=mock_url)\n```\n\n#### Logging\n\nAPI calls made and responses are logged using the [python logging framework](https://docs.python.org/3.7/howto/logging.html#logging-advanced-tutorial).\n\nLogs are generated at debug level containing the XML payloads sent and received. Console output only includes logs of severity WARNINGS and above. This is a characteristic of the logging framework. The following code placed in the application will enable DEBUG to the console with in the format specified.\n\n``` python\nch = logging.StreamHandler()\nch.setLevel(logging.DEBUG)\nformatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')\nch.setFormatter(formatter)\nlogger.addHandler(ch)\n```\n\n## Principals of use\n\n### Fetch first to discover what the next thing does\n\nImagine you are to navigate the Movida API and your **only** knowledge and starting point is the root: `/api`. You would first have to do a GET call that resource to find it contains other collection resources (REST collection) like `titles` and `title_groups` and others. If you made a GET call on the `titles` resource you will notice it has numerous metadata keys and values and `links` to other collection resources including extended `Metadata`. Likewise, you would have to do a GET call on those resources e.g. `assets` to know what sort of resources it has.\n\nThe same applies to using this client library, often we have to do a fetch to access the properties beyond the API root.\n\nThis approach means the library is loosely coupled to Movida. If there are changes in Movida schema it is unlikely to require an update to this library. it also means you do not have to tell the library about your companies custom metadata; the library will discover it and make it available to your application.\n\n#### Except, no need to fetch root/api resource\n\nThere are exceptions to this \"fetch first\" principal. Because fetching the API is a common starting point and what it contains is very predictable, the library pre-populates the properties of the root API object, e.g. it already has a `titles` property:\n\n``` python\nmapi = MovidaAPI(env='staging')\ntitle = mapi.fetch(1001)\n```\n\n#### Except, don't need to fetch the schedulings resource - use add_link() instead\n\nIf you want to avoid unnecessary GET calls when you know the next item beyond the current URL path, you can patch it in to your object. A common use case is the schedule resource; when you fetch it, you find it only contains a link to the schedulings resource and nothing else. We can add the schedulings resource directly and save a GET call.\n\n``` python\nmapi = MovidaAPI(env='staging')\ntitle = titles.fetch(1001)\nschedulings = title.schedule.add_link('schedulings').fetch()\n```\n\n## Features\n\n### Memory efficient Collection processing\n\nThe get_paginated() method of a collection resource e.g. titles is a python generator. It will iterate through each title of the resource returning each title at a time. It will make the GET calls to Movida one page at a time as and when needed (by default with a page size of 50). Only the page of items is held in memory within the collection object at any time.\n\n``` python\nplatform = mapi.platforms.fetch(101)\ntitles = platform.titles.get_paginated()\nfor title in titles:\n print(title.name)\n```\n\n### Image creation and setting the target platforms\n\nImages can be uploaded from a local file or from a remote server location, the method will be determined from the file path given to the `create_image()` method. The return value is an image object representing the created image. Images can be created from a pre-fetched or post fetched object. The encoding type and file name are by default extracted from the given image file name but can be overridden by passing in a dict object. Other metadata can also be passed in. Movida will set values for size and MD5 checksum when the file is processed - this is done asynchronously for remotely sourced images and will be empty in the locally created object.\n\n``` python\nIMAGE_PATH_LOCAL = 'tests/image/1yeVJox3rjo2jBKrrihIMj7uoS9.JPEG'\nmapi = MovidaAPI(env='staging')\ntitle = titles.fetch(1001)\nimage = title.images.create_image(IMAGE_PATH_REMOTE)\nimage.target_platforms.add_platforms(['https://movida.bebanjo.net/api/platforms/51', 'api/platforms/52', 53])\n```\n\nA remote path is also supported.\n\n``` python\nIMAGE_PATH_REMOTE = 'https://mydomain.com/image/1yeVJox3rjo2jBKrrihIMj7uoS9.jpg'\n```\n\nFor existing images there is a risk the addition of a target_platform will fail if it already exists on the image.\n\n``` python\nimages = title.images.fetch()\nfor image in images:\n if image.type == SELECTED_IMAGE_TYPE:\n image = image.fetch()\n image.target_platforms.add_platforms(TARGET_PLATFORMS) # will fail if any exists already\n```\n\nTo avoid the possible failure do:\n\n``` python\n image = image.fetch()\n image.target_platforms = image.target_platforms.fetch() # get existing target platforms\n image.target_platforms.add_platforms(TARGET_PLATFORMS) # will not add platform if already exists\n```\n\nNote the long code line in the above:\n\n``` python\nimage.target_platforms = image.target_platforms.fetch()\n```\n\nThis is necessary when target_platforms is of class Fetcher; it cannot *upgrade* its own class to Collection. A helper is available to make the code a little cleaner.\n\n``` python\nfrom bebanjo.utils import replace_self_fetch\n\nreplace_self_fetch(image.target_platforms)\n```\n\n\n### Seamlessly step between Movida and Sequence\n\nAs long as you have valid credentials loaded that are valid for Movida and Sequence, then the library does is agnostic to the resource referenced in an object property. E.g. the jobs resource on a Movida scheduling refers to a resource in Sequence and accessing that resource will automatically trigger authentication with Sequence.\n\n### String representations of an object\n\n#### Inspect utility\n\nInspect the properties of a title; first class metadata, extended metadata and links to related objects that can be fetched for further inspection. It prints directly to the console. It is intended for debugging and interactive sessions.\n\n``` python\nfrom bebanjo import inspect\ninspect(title)\n```\n\nOutput:\n\n```\nInstance of Title (//titles/1001)\n > name: Winter Is Coming\n > title: Winter Is Coming\n > external_id: 63056\n > title_type: 'episode\n > episode_number: 1\n > tags:\n Metadata:\n > short_description: The \"one\" where winter's comming\n > air_date: 2011-04-24\n > content_source: The Movie Database\n > subgenres: ['Action', 'Fantasy']\n > download_rights: True\n Getters:\n > assets\n > availability_windows\n > blackouts\n > images\n > licensor\n > linear_schedulings\n > metadata\n > rights\n > rules\n > schedule\n > title_groups\n > trailers\n ```\n\n#### Fetch a title by external ID\n\n``` python\ntitle = mapi.titles.fetch(1001)\n```\n\n### Fetch title by external_id and include extended metadata and images\n\n``` python\ntitle = mapi.titles.fetch(external_id='HI2MEUK/377364', expand=['metadata', 'images'])\n```\n\n### Fetch asset by name\n\n``` python\nasset = mapi.assets.fetch(name='BBJ12345A')\n```\n\n### Create an object using the parent resource object\n\nNo need to fetch the collection resource first as only it's URL is needed to create an object inside this resource.\n\n``` python\nmapi = MovidaAPI(env='staging')\nmeta = {'name': 'The Ring'}\nrelations = {'licensor': 'api/licensors/4'}\nmapi.titles.create(meta, relations)\n```\n\n> In the above example, if name were not specified, Movida would complain with a 422 response because `name` is mandatory for a title. Likewise if a metadata key or value is invalid, a 422 response would also result.\n\n### Read the metadata of an object\n\nAccess the values of metadata like they're python dictionary.\n\n``` python\n# first class metadata\nname = title['name']\n# extended metadata\ndescription = title.metadata['description']\n```\n\n### Update a title in Movida\n\n``` python\n# first class metadata\ntitle.update({'name': 'The Ring'}, {'licensor': 'api/licensors/1201'})\n# extended metadata requires a seperate call to Movida\ntitle.metadata.update({'name': 'abcd\u00e9f', 'description': 'Simon looses the ring.'})\n```\n\n### Build a dict of platform names to IDs\n\n``` python\nid_from_platform = {}\nfor platform in mapi.platforms.fetch():\n id_from_platform[platform.name] = platform.id\n```", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://gitlab.com/hi2meuk/bebanjo-api", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "bebanjo-api-hi2meuk", "package_url": "https://pypi.org/project/bebanjo-api-hi2meuk/", "platform": "", "project_url": "https://pypi.org/project/bebanjo-api-hi2meuk/", "project_urls": { "Homepage": "https://gitlab.com/hi2meuk/bebanjo-api" }, "release_url": "https://pypi.org/project/bebanjo-api-hi2meuk/1.3.0/", "requires_dist": null, "requires_python": ">=3", "summary": "A client library for interacting with Bebanjo's Movida and Seqeuence APIs.", "version": "1.3.0" }, "last_serial": 5991912, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "12d7fcd6adbd96e3b477e51b98a2ffec", "sha256": "a2e73bf6f7b4a70277cd4df591b1ba0f65750a41f206542db7bfe7bda7c13ce9" }, "downloads": -1, "filename": "bebanjo-api-hi2meuk-1.0.tar.gz", "has_sig": false, "md5_digest": "12d7fcd6adbd96e3b477e51b98a2ffec", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3", "size": 19789, "upload_time": "2019-06-23T18:43:49", "url": "https://files.pythonhosted.org/packages/49/cc/3acf240737440ad10a13359ee48679afd264185fe03bae6cb5326f0e3c9b/bebanjo-api-hi2meuk-1.0.tar.gz" } ], "1.1": [ { "comment_text": "", "digests": { "md5": "d44036888aca1dd0955428e2db112716", "sha256": "e6d14dcebba8c6f017c867def1934e38e1581f416065a7d12fdfc78c171723f7" }, "downloads": -1, "filename": "bebanjo-api-hi2meuk-1.1.tar.gz", "has_sig": false, "md5_digest": "d44036888aca1dd0955428e2db112716", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3", "size": 21887, "upload_time": "2019-07-16T18:42:16", "url": "https://files.pythonhosted.org/packages/70/ea/a26e138721ad96e8386329ea923b7a3dc3ddf1efdd03bea79f894a31dcf5/bebanjo-api-hi2meuk-1.1.tar.gz" } ], "1.2": [ { "comment_text": "", "digests": { "md5": "1dece043fe342a7175ea7b2781efbf77", "sha256": "f4590f7a3f55680135c1c5dd6b12caca341fd840b41b29f9a79837482646967e" }, "downloads": -1, "filename": "bebanjo-api-hi2meuk-1.2.tar.gz", "has_sig": false, "md5_digest": "1dece043fe342a7175ea7b2781efbf77", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3", "size": 21685, "upload_time": "2019-08-06T06:31:46", "url": "https://files.pythonhosted.org/packages/29/34/936e246343107d34ccd6d957224aac0cba3c7afc9f3cef6444df103a4f25/bebanjo-api-hi2meuk-1.2.tar.gz" } ], "1.2.1": [ { "comment_text": "", "digests": { "md5": "ccdec956ed7c36d22e32fc98def02179", "sha256": "2ad59ecfa92e2c09cc2636499cc8defb9cec0b453b1c44ced850492ca29f102a" }, "downloads": -1, "filename": "bebanjo-api-hi2meuk-1.2.1.tar.gz", "has_sig": false, "md5_digest": "ccdec956ed7c36d22e32fc98def02179", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3", "size": 26077, "upload_time": "2019-10-07T20:10:58", "url": "https://files.pythonhosted.org/packages/aa/54/bb83d389345f966d46ec639e5a54c07f7541ed40a5a52315dc027902bba5/bebanjo-api-hi2meuk-1.2.1.tar.gz" } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "71fd5c1a50b912051c6cf9110d225b37", "sha256": "46591c28894a5544fd95edc6d84b3e4f707ee96d549f8f84c1e4f863d134227c" }, "downloads": -1, "filename": "bebanjo-api-hi2meuk-1.3.0.tar.gz", "has_sig": false, "md5_digest": "71fd5c1a50b912051c6cf9110d225b37", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3", "size": 26146, "upload_time": "2019-10-17T19:19:10", "url": "https://files.pythonhosted.org/packages/d9/01/f3e56a0d8d437238e797e1df25173d49697e75af1fec2db744e6a1b88db1/bebanjo-api-hi2meuk-1.3.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "71fd5c1a50b912051c6cf9110d225b37", "sha256": "46591c28894a5544fd95edc6d84b3e4f707ee96d549f8f84c1e4f863d134227c" }, "downloads": -1, "filename": "bebanjo-api-hi2meuk-1.3.0.tar.gz", "has_sig": false, "md5_digest": "71fd5c1a50b912051c6cf9110d225b37", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3", "size": 26146, "upload_time": "2019-10-17T19:19:10", "url": "https://files.pythonhosted.org/packages/d9/01/f3e56a0d8d437238e797e1df25173d49697e75af1fec2db744e6a1b88db1/bebanjo-api-hi2meuk-1.3.0.tar.gz" } ] }