{ "info": { "author": "Dmitry Viskov", "author_email": "dmitry.viskov@webenterprise.ru", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Framework :: Flask", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Security", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "LTI 1.3 Advantage Tool implementation in Python\n===============================================\n\n.. image:: https://img.shields.io/pypi/v/PyLTI1p3\n :scale: 100%\n :target: https://pypi.python.org/pypi/PyLTI1p3\n :alt: PyPI\n\n.. image:: https://img.shields.io/pypi/pyversions/PyLTI1p3\n :scale: 100%\n :target: https://www.python.org/\n :alt: Python\n\n.. image:: https://travis-ci.com/dmitry-viskov/pylti1.3.svg?branch=master\n :scale: 100%\n :target: https://travis-ci.com/dmitry-viskov/pylti1.3\n :alt: Build Status\n\n.. image:: https://img.shields.io/github/license/dmitry-viskov/pylti1.3\n :scale: 100%\n :target: https://raw.githubusercontent.com/dmitry-viskov/pylti1.3/master/LICENSE\n :alt: MIT\n\n\nThis project is a Python implementation of the similar `PHP tool`_.\nThis library contains adapters for use with the Django and Flask web frameworks. However, there are no difficulties with adapting it to other frameworks; you just need to re-implement the ``OIDCLogin`` and ``MessageLaunch`` classes as it is already done in existing adapters.\n\n.. _PHP tool: https://github.com/IMSGlobal/lti-1-3-php-library\n\nUsage Examples\n=================\n\nDjango: https://github.com/dmitry-viskov/pylti1.3-django-example\n\nFlask: https://github.com/dmitry-viskov/pylti1.3-flask-example\n\nConfiguration\n=============\n\nTo configure your own tool, you may use built-in adapters:\n\n.. code-block:: python\n\n from pylti1p3.tool_config import ToolConfJsonFile\n tool_conf = ToolConfJsonFile('path/to/json')\n\n from pylti1p3.tool_config import ToolConfDict\n settings = {\n \"\": { }, # one issuer ~ one client-id (outdated and not recommended)\n \"\": [{ }, { }] # one issuer ~ many client-ids (recommended method)\n }\n private_key = '...'\n public_key = '...'\n tool_conf = ToolConfDict(settings)\n\n client_id = '...' # must be set if implementing the \"one issuer ~ many client-ids\" concept\n\n tool_conf.set_private_key(iss, private_key, client_id=client_id)\n tool_conf.set_public_key(iss, public_key, client_id=client_id)\n\nor create your own implementation. The ``pylti1p3.tool_config.ToolConfAbstract`` interface must be fully implemented for this to work.\nThe concept of ``one issuer ~ many client-ids`` is the recommended way to organize configs and may be useful in the case of integration with Canvas (https://canvas.instructure.com)\nor other Cloud LMS-es where the platform doesn't change ``iss`` for each customer.\n\nIn the case of the Django Framework, you may use ``DjangoDbToolConf`` (see `Configuration using Django Admin UI`_ section below).\n\n\nExample of a JSON config:\n\n.. code-block:: javascript\n\n {\n \"iss1\": [{\n \"default\": true,\n \"client_id\": \"client_id1\",\n \"auth_login_url\": \"auth_login_url1\",\n \"auth_token_url\": \"auth_token_url1\",\n \"auth_audience\": null,\n \"key_set_url\": \"key_set_url1\",\n \"key_set\": null,\n \"private_key_file\": \"private.key\",\n \"public_key_file\": \"public.key\",\n \"deployment_ids\": [\"deployment_id1\", \"deployment_id2\"]\n }, {\n \"default\": false,\n \"client_id\": \"client_id2\",\n \"auth_login_url\": \"auth_login_url2\",\n \"auth_token_url\": \"auth_token_url2\",\n \"auth_audience\": null,\n \"key_set_url\": \"key_set_url2\",\n \"key_set\": null,\n \"private_key_file\": \"private.key\",\n \"public_key_file\": \"public.key\",\n \"deployment_ids\": [\"deployment_id3\", \"deployment_id4\"]\n }],\n \"iss2\": [ ],\n \"iss3\": { }\n }\n\n\n| ``default (bool)`` - this iss config will be used in case if client-id was not passed on the login step\n| ``client_id`` - this is the id received in the 'aud' during a launch\n| ``auth_login_url`` - the platform's OIDC login endpoint\n| ``auth_token_url`` - the platform's service authorization endpoint\n| ``auth_audience`` - the platform's OAuth2 Audience (aud). Is used to get platform's access token. Usually the same as \"auth_token_url\" and could be skipped but in the common case could be a different url\n| ``key_set_url`` - the platform's JWKS endpoint\n| ``key_set`` - in case if platform's JWKS endpoint somehow unavailable you may paste JWKS here\n| ``private_key_file`` - relative path to the tool's private key\n| ``public_key_file`` - relative path to the tool's public key\n| ``deployment_ids (list)`` - The deployment_id passed by the platform during launch\n\nUsage with Django\n=================\n\n.. _Configuration:\n\nConfiguration using Django Admin UI\n-----------------------------------\n\n.. code-block:: python\n\n # settings.py\n\n INSTALLED_APPS = [\n 'django.contrib.admin',\n ...\n 'pylti1p3.contrib.django.lti1p3_tool_config'\n ]\n\n # urls.py\n\n urlpatterns = [\n ...\n path('admin/', admin.site.urls),\n ...\n ]\n\n # views.py\n\n from pylti1p3.contrib.django import DjangoDbToolConf\n\n tool_conf = DjangoDbToolConf()\n\n\nOpen Id Connect Login Request\n-----------------------------\n\nLTI 1.3 uses a modified version of the OpenId Connect third party initiate login flow. This means that to do an LTI 1.3 launch, you must first receive a login initialization request and return to the platform.\n\nTo handle this request, you must first create a new ``OIDCLogin`` (or ``DjangoOIDCLogin``) object:\n\n.. code-block:: python\n\n from pylti1p3.contrib.django import DjangoOIDCLogin\n\n oidc_login = DjangoOIDCLogin(request, tool_conf)\n\nYou must now configure your login request with a return url (this must be preconfigured and white-listed in the tool).\nIf a redirect url is not given or the registration does not exist, a ``pylti1p3.exception.OIDC_Exception`` will be thrown.\n\n.. code-block:: python\n\n try:\n oidc_login.redirect(get_launch_url(request))\n except OIDC_Exception:\n # display error page\n log.error('Error doing OIDC login')\n\nWith the redirect, we can now redirect the user back to the tool.\nThere are three ways to do this:\n\nThis will add a HTTP 302 location header:\n\n.. code-block:: python\n\n oidc_login.redirect(get_launch_url(request))\n\nThis will display some JavaScript to do the redirect instead of using a HTTP 302:\n\n.. code-block:: python\n\n oidc_login.redirect(get_launch_url(request), js_redirect=True)\n\nYou can also get the url you need to redirect to, with all of the necessary query parameters (if you would prefer to redirect in a custom way):\n\n.. code-block:: python\n\n redirect_obj = oidc_login.get_redirect_object()\n redirect_url = redirect_obj.get_redirect_url()\n\nThe redirect is done and we can move on to the launch.\n\nLTI Message Launches\n--------------------\n\nNow that we have done the OIDC log, the platform will launch back to the tool. To handle this request, we first need to create a new ``MessageLaunch`` (or ``DjangoMessageLaunch``) object.\n\n.. code-block:: python\n\n message_launch = DjangoMessageLaunch(request, tool_conf)\n\nOnce we have the message launch, we can validate it. Validation is transparent - it's done once before you try to access the message body:\n\n.. code-block:: python\n\n try:\n launch_data = message_launch.get_launch_data()\n except LtiException:\n log.error('Launch validation failed')\n\nYou may do it more explicitly:\n\n.. code-block:: python\n\n try:\n launch_data = message_launch.set_auto_validation(enable=False).validate()\n except LtiException:\n log.error('Launch validation failed')\n\nNow that we know the launch is valid, we can find out more information about the launch.\n\nTo check if we have a resource launch or a deep linking launch:\n\n.. code-block:: python\n\n if message_launch.is_resource_launch():\n # Resource Launch!\n elif message_launch.is_deep_link_launch():\n # Deep Linking Launch!\n else:\n # Unknown launch type\n\nTo check which services we have access to:\n\n.. code-block:: python\n\n if message_launch.has_ags():\n # Has Assignments and Grades Service\n if message_launch.has_nrps():\n # Has Names and Roles Service\n\nUsage with Flask\n================\n\nOpen Id Connect Login Request\n-----------------------------\n\nThis is a draft of an API endpoint. Wrap it in a library of your choice.\n\nCreate a ``FlaskRequest`` adapter. Then create an instance of ``FlaskOIDCLogin``. The ``redirect`` method will return an instance of ``werkzeug.wrappers.Response`` that points to the LTI platform if login was successful. Make sure to handle exceptions.\n\n.. code-block:: python\n\n from flask import request, session\n from pylti1p3.flask_adapter import (FlaskRequest, FlaskOIDCLogin)\n\n def login(request_params_dict):\n\n tool_conf = ... # See Configuration chapter above\n\n # FlaskRequest by default use flask.request and flask.session\n # so in this case you may define request object without any arguments:\n\n request = FlaskRequest()\n\n # in case of using different request object (for example webargs or something like this)\n # you may pass your own values:\n\n request = FlaskRequest(\n cookies=request.cookies,\n session=session,\n request_data=request_params_dict,\n request_is_secure=request.is_secure\n )\n\n oidc_login = FlaskOIDCLogin(\n request=request,\n tool_config=tool_conf,\n session_service=FlaskSessionService(request),\n cookie_service=FlaskCookieService(request)\n )\n\n return oidc_login.redirect(request.get_param('target_link_uri'))\n\nLTI Message Launches\n--------------------\n\nThis is a draft of an API endpoint. Wrap it in a library of your choice.\n\nCreate a ``FlaskRequest`` adapter. Then create an instance of ``FlaskMessageLaunch``. This lets you access data from the LTI launch message if the launch was successful. Make sure to handle exceptions.\n\n.. code-block:: python\n\n from flask import request, session\n from werkzeug.utils import redirect\n from pylti1p3.flask_adapter import (FlaskRequest, FlaskMessageLaunch)\n\n def launch(request_params_dict):\n\n tool_conf = ... # See Configuration chapter above\n\n request = FlaskRequest()\n\n # or\n\n request = FlaskRequest(\n cookies=...,\n session=...,\n request_data=...,\n request_is_secure=...\n )\n\n message_launch = FlaskMessageLaunch(\n request=request,\n tool_config=tool_conf\n )\n\n email = message_launch.get_launch_data().get('email')\n\n # Place your user creation/update/login logic\n # and redirect to tool content here\n\nAccessing Cached Launch Requests\n================================\n\nIt is likely that you will want to refer back to a launch later during subsequent requests. This is done using the launch id to identify a cached request. The launch id can be found using:\n\n.. code-block:: python\n\n launch_id = message_launch.get_launch_id()\n\nOnce you have the launch id, you can link it to your session and pass it along as a query parameter.\n\nRetrieving a launch using the launch id can be done using:\n\n.. code-block:: python\n\n message_launch = DjangoMessageLaunch.from_cache(launch_id, request, tool_conf)\n\nOnce retrieved, you can call any of the methods on the launch object as normal, e.g.\n\n.. code-block:: python\n\n if message_launch.has_ags():\n # Has Assignments and Grades Service\n\nDeep Linking Responses\n======================\n\nIf you receive a deep linking launch, it is very likely that you are going to want to respond to the deep linking request with resources for the platform.\n\nTo create a deep link response, you will need to get the deep link for the current launch:\n\n.. code-block:: python\n\n deep_link = message_launch.get_deep_link()\n\nWe now need to create ``pylti1p3.deep_link_resource.DeepLinkResource`` to return:\n\n.. code-block:: python\n\n resource = DeepLinkResource()\n resource.set_url(\"https://my.tool/launch\")\\\n .set_custom_params({'my_param': my_param})\\\n .set_title('My Resource')\n\nEverything is now set to return the resource to the platform. There are two methods of doing this.\n\nThe following method will output the html for an aut-posting form for you.\n\n.. code-block:: python\n\n deep_link.output_response_form([resource1, resource2])\n\nAlternatively you can just request the signed JWT that will need posting back to the platform by calling.\n\n.. code-block:: python\n\n deep_link.get_response_jwt([resource1, resource2])\n\nNames and Roles Service\n=======================\n\nBefore using names and roles, you should check that you have access to it:\n\n.. code-block:: python\n\n if not message_launch.has_nrps():\n raise Exception(\"Don't have names and roles!\")\n\nOnce we know we can access it, we can get an instance of the service from the launch.\n\n.. code-block:: python\n\n nrps = message_launch.get_nrps()\n\nFrom the service we can get a list of all members by calling:\n\n.. code-block:: python\n\n members = nrps.get_members()\n\nTo get some specific page with the members:\n\n.. code-block:: python\n\n members, next_page_url = nrps.get_members_page(page_url)\n\nAssignments and Grades Service\n==============================\n\nBefore using assignments and grades, you should check that you have access to it:\n\n.. code-block:: python\n\n if not launch.has_ags():\n raise Exception(\"Don't have assignments and grades!\")\n\nOnce we know we can access it, we can get an instance of the service from the launch:\n\n.. code-block:: python\n\n ags = launch.get_ags()\n\nTo pass a grade back to the platform, you will need to create a ``pylti1p3.grade.Grade`` object and populate it with the necessary information:\n\n.. code-block:: python\n\n gr = Grade()\n gr.set_score_given(earned_score)\\\n .set_score_maximum(100)\\\n .set_timestamp(datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S+0000'))\\\n .set_activity_progress('Completed')\\\n .set_grading_progress('FullyGraded')\\\n .set_user_id(external_user_id)\n\nTo send the grade to the platform we can call:\n\n.. code-block:: python\n\n ags.put_grade(gr)\n\nThis will put the grade into the default provided lineitem. If no default lineitem exists it will create one.\n\nIf you want to send multiple types of grade back, that can be done by specifying a ``pylti1p3.lineitem.LineItem``:\n\n.. code-block:: python\n\n line_item = LineItem()\n line_item.set_tag('grade')\\\n .set_score_maximum(100)\\\n .set_label('Grade')\n\n ags.put_grade(gr, line_item)\n\nIf a lineitem with the same ``tag`` exists, that lineitem will be used, otherwise a new lineitem will be created.\nAdditional methods:\n\n.. code-block:: python\n\n # Get one page with line items\n items_lst, next_page = ags.get_lineitems_page()\n\n # Get list of all available line items\n items_lst = ags.get_lineitems()\n\n # Find line item by ID\n item = ags.find_lineitem_by_id(ln_id)\n\n # Find line item by tag\n item = ags.find_lineitem_by_tag(ln_tag)\n\n # Return all grades for the passed line item (across all users enrolled in the line item's context)\n grades = ags.get_grades(ln)\n\nData privacy launch\n===================\n\nData Privacy Launch is a new optional LTI 1.3 message type that allows LTI-enabled tools to assist administrative\nusers in managing and executing requests related to data privacy.\n\n.. code-block:: python\n\n data_privacy_launch = message_launch.is_data_privacy_launch()\n if data_privacy_launch:\n user = message_launch.get_data_privacy_launch_user()\n\n\nSubmission review\n=================\n\nSubmission review provides a standard way for an instructor or student to launch back from a platform's gradebook\nto the tool where the interaction took place to display the learner's submission for a particular line item.\n\n.. code-block:: python\n\n if launch.is_submission_review_launch()\n user = launch.get_submission_review_user()\n ags = launch.get_ags()\n lineitem = ags.get_lineitem()\n submission_review = lineitem.get_submission_review()\n\n\nCourse Group Service\n====================\n\nCommunicates to the tool the groups available in the course and their respective enrollment.\n\n.. code-block:: python\n\n if launch.has_cgs()\n cgs = launch.get_cgs()\n\n # Get all available groups\n groups = cgs.get_groups()\n\n # Get groups for some user\n user_id = '0ae836b9-7fc9-4060-006f-27b2066ac545'\n groups = cgs.get_groups(user_id)\n\n # Get all sets\n if cgs.has_sets():\n sets = cgs.get_sets()\n sets_with_groups = cgs.get_sets(include_groups=True)\n\n\nCheck user's role after LTI launch\n==================================\n\n.. code-block:: python\n\n user_is_staff = message_launch.check_staff_access()\n user_is_student = message_launch.check_student_access())\n user_is_teacher = message_launch.check_teacher_access()\n user_is_teaching_assistant = message_launch.check_teaching_assistant_access()\n user_is_designer = message_launch.check_designer_access()\n user_is_observer = message_launch.check_observer_access()\n user_is_transient = message_launch.check_transient()\n\nCookies issues in the iframes\n=============================\n\nSome browsers may deny requests to save cookies in the iframes. For example, `Google Chrome (from ver.80 onwards) denies requests to save`_ all cookies in\nthe iframes except cookies with the flags ``Secure`` (i.e HTTPS usage) and ``SameSite=None``. `Safari denies requests to save`_\nall third-party cookies by default. The ``pylti1p3`` library contains workarounds for such behaviours:\n\n.. _Google Chrome (from ver.80 onwards) denies requests to save: https://blog.heroku.com/chrome-changes-samesite-cookie\n.. _Safari denies requests to save: https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/\n\n.. code-block:: python\n\n def login():\n ...\n return oidc_login\\\n .enable_check_cookies()\\\n .redirect(target_link_uri)\n\nAfter this, the special JS code will try to write and then read test cookie instead of redirect. The user will see a\n`special page`_ that will ask them to open the current URL in the new window if cookies are unavailable. If\ncookies are allowed, the user will be transparently redirected to the next page. All texts are configurable with passing arguments:\n\n.. _special page: https://raw.githubusercontent.com/dmitry-viskov/repos-assets/master/pylti1p3/examples/cookies-check/001.png\n\n.. code-block:: python\n\n oidc_login.enable_check_cookies(main_msg, click_msg, loading_msg)\n\nYou may also have troubles with the default framework sessions because the ``pylti1p3`` library can't control your framework\nsettings connected with the session ID cookie. Without necessary settings, the user's session could be unavailable in the\ncase of iframe usage. To avoid this, it is recommended to change the default session adapter to the new cache\nadapter (with a memcache/redis backend) and as a consequence, allow the library to set its own LTI 1.3 session id cookie\nthat will be set with all necessary params like ``Secure`` and ``SameSite=None``.\n\nDjango cache data storage\n-------------------------\n\n.. code-block:: python\n\n from pylti1p3.contrib.django import DjangoCacheDataStorage\n\n def login(request):\n ...\n launch_data_storage = DjangoCacheDataStorage(cache_name='default')\n oidc_login = DjangoOIDCLogin(request, tool_conf, launch_data_storage=launch_data_storage)\n\n def launch(request):\n ...\n launch_data_storage = DjangoCacheDataStorage(cache_name='default')\n message_launch = DjangoMessageLaunch(request, tool_conf, launch_data_storage=launch_data_storage)\n\n def restore_launch(request):\n ...\n launch_data_storage = get_launch_data_storage(cache_name='default')\n message_launch = DjangoMessageLaunch.from_cache(launch_id, request, tool_conf,\n launch_data_storage=launch_data_storage)\n\nFlask cache data storage\n-------------------------\n\n.. code-block:: python\n\n from flask_caching import Cache\n from pylti1p3.contrib.flask import FlaskCacheDataStorage\n\n cache = Cache(app)\n\n def login():\n ...\n launch_data_storage = FlaskCacheDataStorage(cache)\n oidc_login = DjangoOIDCLogin(request, tool_conf, launch_data_storage=launch_data_storage)\n\n def launch():\n ...\n launch_data_storage = FlaskCacheDataStorage(cache)\n message_launch = DjangoMessageLaunch(request, tool_conf, launch_data_storage=launch_data_storage)\n\n def restore_launch():\n ...\n launch_data_storage = FlaskCacheDataStorage(cache)\n message_launch = DjangoMessageLaunch.from_cache(launch_id, request, tool_conf,\n launch_data_storage=launch_data_storage)\n\nCache for Public Key\n====================\n\nThe library will try to fetch the platform's public key every time on the message launch step. This public key may be stored in cache\n(memcache/redis) to speed-up the launch process:\n\n.. code-block:: python\n\n # Django cache storage:\n launch_data_storage = DjangoCacheDataStorage()\n\n # Flask cache storage:\n launch_data_storage = FlaskCacheDataStorage(cache)\n\n message_launch.set_public_key_caching(launch_data_storage, cache_lifetime=7200)\n\n\nAPI to get JWKS\n===============\n\nYou may generate JWKS from a Tool Config object:\n\n.. code-block:: python\n\n tool_conf.set_public_key(iss, public_key, client_id=client_id)\n jwks_dict = tool_conf.get_jwks() # {\"keys\": [{ ... }]}\n\n # or you may specify iss and client_id:\n jwks_dict = tool_conf.get_jwks(iss, client_id) # {\"keys\": [{ ... }]}\n\nDo not forget to set a public key as without it, JWKS cannot be generated.\nYou may also generate JWK for any public key using the construction below:\n\n.. code-block:: python\n\n from pylti1p3.registration import Registration\n\n jwk_dict = Registration.get_jwk(public_key)\n # {\"e\": ..., \"kid\": ..., \"kty\": ..., \"n\": ..., \"alg\": ..., \"use\": ...}\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/dmitry-viskov/pylti1.3", "keywords": "pylti,pylti1p3,lti,lti1.3,lti1p3,django,flask", "license": "MIT", "maintainer": "Dmitry Viskov", "maintainer_email": "", "name": "PyLTI1p3", "package_url": "https://pypi.org/project/PyLTI1p3/", "platform": null, "project_url": "https://pypi.org/project/PyLTI1p3/", "project_urls": { "Homepage": "https://github.com/dmitry-viskov/pylti1.3" }, "release_url": "https://pypi.org/project/PyLTI1p3/1.11.0/", "requires_dist": [ "pyjwt (>=1.5)", "requests", "typing ; python_version < \"3.5\"", "jwcrypto (==0.9.1) ; python_version >= \"2\" and python_version < \"3\"", "jwcrypto ; python_version >= \"3\"" ], "requires_python": "", "summary": "LTI 1.3 Advantage Tool implementation in Python", "version": "1.11.0", "yanked": false, "yanked_reason": null }, "last_serial": 13580296, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "223b9bb9df840164c6dd04868f5a866b", "sha256": "cf1573e7d70d27094cd4f550e02a770b1590d55f012ab27c4f3bee700fd48e36" }, "downloads": -1, "filename": "PyLTI1p3-1.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "223b9bb9df840164c6dd04868f5a866b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 24798, "upload_time": "2019-08-13T11:23:05", "upload_time_iso_8601": "2019-08-13T11:23:05.358400Z", "url": "https://files.pythonhosted.org/packages/14/05/9403b3e5aee6103c0493e6d8a60bfa8308ff6dae4990ce25658a0980800b/PyLTI1p3-1.0.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "2d89f903f24153ca7627652978ac49d0", "sha256": "ca94ffa611bfc19c7a55a742b2086e508d424d06c99d9319184b701f75060b16" }, "downloads": -1, "filename": "PyLTI1p3-1.0.0.tar.gz", "has_sig": false, "md5_digest": "2d89f903f24153ca7627652978ac49d0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20603, "upload_time": "2019-08-13T11:23:08", "upload_time_iso_8601": "2019-08-13T11:23:08.284057Z", "url": "https://files.pythonhosted.org/packages/98/d4/adf9e8f414570023ff52e7e20c41789c4839c0d2d9eae8f3e3f8ef534880/PyLTI1p3-1.0.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "717e672bab7b2a579b3d1ad88e45d39e", "sha256": "349fe03405119fb6ee0415b78925dad8e54cd05f3ba227c4ba2564e7780bc547" }, "downloads": -1, "filename": "PyLTI1p3-1.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "717e672bab7b2a579b3d1ad88e45d39e", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 24959, "upload_time": "2019-08-16T13:15:55", "upload_time_iso_8601": "2019-08-16T13:15:55.837055Z", "url": "https://files.pythonhosted.org/packages/80/02/7370d0555521620ccbfa1d3e6219328da7520af666581db79eace4e40583/PyLTI1p3-1.1.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "4aeb246cd68033e01fc12ade78680248", "sha256": "32124ed60360b1e5713c15e1565ff4acbde8e12040ca984c375e7a766f30edeb" }, "downloads": -1, "filename": "PyLTI1p3-1.1.0.tar.gz", "has_sig": false, "md5_digest": "4aeb246cd68033e01fc12ade78680248", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20748, "upload_time": "2019-08-16T13:15:58", "upload_time_iso_8601": "2019-08-16T13:15:58.878470Z", "url": "https://files.pythonhosted.org/packages/0b/65/58054dc66cb8ee44e67df396b90971ee176c9f206c0ef04cff7333f34e28/PyLTI1p3-1.1.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "b0893ead9fbe63bda60da440198253c8", "sha256": "527fb69a68a69bcd8412f3c94ee2792e8f2696d4baf1f82365789ee558198569" }, "downloads": -1, "filename": "PyLTI1p3-1.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b0893ead9fbe63bda60da440198253c8", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 24959, "upload_time": "2019-08-16T15:19:33", "upload_time_iso_8601": "2019-08-16T15:19:33.283037Z", "url": "https://files.pythonhosted.org/packages/3b/47/07e21f9b73f517905da0959e2fb48275e7f422a832b257ac64ac401e9750/PyLTI1p3-1.1.1-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "0ce2825b504f3a9becbd2392be85d236", "sha256": "4b8f2c137399d1bfbe235fa9246266723358d434bf8acbd7c733b9ebd06c0cef" }, "downloads": -1, "filename": "PyLTI1p3-1.1.1.tar.gz", "has_sig": false, "md5_digest": "0ce2825b504f3a9becbd2392be85d236", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20747, "upload_time": "2019-08-16T15:19:37", "upload_time_iso_8601": "2019-08-16T15:19:37.392438Z", "url": "https://files.pythonhosted.org/packages/28/7d/c840d2de0890327fe33f7e5d4dc360dd5951dc33e34584f54afa04c81be8/PyLTI1p3-1.1.1.tar.gz", "yanked": false, "yanked_reason": null } ], "1.10.0": [ { "comment_text": "", "digests": { "md5": "277ab8d533f0607f4de361b94bd0b0a4", "sha256": "0b66c1bc6b8cceaface857fe5bd500b575e852e5c242b196a738cfd7e2fd95f4" }, "downloads": -1, "filename": "PyLTI1p3-1.10.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "277ab8d533f0607f4de361b94bd0b0a4", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 61946, "upload_time": "2021-12-05T20:50:51", "upload_time_iso_8601": "2021-12-05T20:50:51.592048Z", "url": "https://files.pythonhosted.org/packages/ca/ee/0e5983b61bfc17eacaf72b22a45b0d21fc89c958136edd9777c7b97a4973/PyLTI1p3-1.10.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "995e14b0327f0ab0cb37e3b44d79dee0", "sha256": "13026f65541562cf46a9130949449048ae47fa8db31615dadc323f84e73f0297" }, "downloads": -1, "filename": "PyLTI1p3-1.10.0.tar.gz", "has_sig": false, "md5_digest": "995e14b0327f0ab0cb37e3b44d79dee0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 45964, "upload_time": "2021-12-05T20:50:53", "upload_time_iso_8601": "2021-12-05T20:50:53.543417Z", "url": "https://files.pythonhosted.org/packages/1f/9f/704d23584d85dcc66ad275f89f3d2ff62da346bbb7e19e9791cce57a3747/PyLTI1p3-1.10.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.11.0": [ { "comment_text": "", "digests": { "md5": "04b1aa26a598fc7c25eb0e92b2614efd", "sha256": "3525c46310cf42a10c4c221c6539f66ed0953b843caec6f50ad6944d84978587" }, "downloads": -1, "filename": "PyLTI1p3-1.11.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "04b1aa26a598fc7c25eb0e92b2614efd", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 62121, "upload_time": "2022-04-21T15:01:16", "upload_time_iso_8601": "2022-04-21T15:01:16.613409Z", "url": "https://files.pythonhosted.org/packages/c9/bc/90fc6fa6fd8bfeaaae7086d4f3af68074530d5b1a528a46b6506fd350f5c/PyLTI1p3-1.11.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "ea29a7c64e2acc5adaacaf2c30ba9de3", "sha256": "4d029715b67158f7746aec4f42d0abf8221c037b3923e9aacfae888a1095647a" }, "downloads": -1, "filename": "PyLTI1p3-1.11.0.tar.gz", "has_sig": false, "md5_digest": "ea29a7c64e2acc5adaacaf2c30ba9de3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 46244, "upload_time": "2022-04-21T15:01:21", "upload_time_iso_8601": "2022-04-21T15:01:21.602594Z", "url": "https://files.pythonhosted.org/packages/c7/f8/6617d26cd0dccfbd5782438b1ac1a1e83326bb7ddf01bec7df8618b22655/PyLTI1p3-1.11.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "69e44cdc0270d01a865f4f6de6b75890", "sha256": "877445187873ac22e49f116f27e3418b9ae0cd740f6b8f4f50bb7256de4d674b" }, "downloads": -1, "filename": "PyLTI1p3-1.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "69e44cdc0270d01a865f4f6de6b75890", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25125, "upload_time": "2019-08-20T17:19:44", "upload_time_iso_8601": "2019-08-20T17:19:44.086855Z", "url": "https://files.pythonhosted.org/packages/1d/22/3ed2fe943c2e6cf083b86caf07f2ce07da797a47ff5841642d9e0573e30c/PyLTI1p3-1.2.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "005fc4b4e26d436422163c57fc60d3a5", "sha256": "69f76b3244a7f7d9f058faed3f5b5e43d9d00dbd0bc0bc5b8bb35965a69dfb96" }, "downloads": -1, "filename": "PyLTI1p3-1.2.0.tar.gz", "has_sig": false, "md5_digest": "005fc4b4e26d436422163c57fc60d3a5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20908, "upload_time": "2019-08-20T17:19:46", "upload_time_iso_8601": "2019-08-20T17:19:46.346945Z", "url": "https://files.pythonhosted.org/packages/2e/31/c55428080a773447eb6d779bcc19e85773c74d49c9141ca2c899f9a0c38a/PyLTI1p3-1.2.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "33ff593d5739a0e3d87376b3b275f5f8", "sha256": "82293182697148feee7686e3ea029357d3cae45884b06c354de82cc8148cc299" }, "downloads": -1, "filename": "PyLTI1p3-1.3.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "33ff593d5739a0e3d87376b3b275f5f8", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25393, "upload_time": "2019-08-22T13:17:59", "upload_time_iso_8601": "2019-08-22T13:17:59.357282Z", "url": "https://files.pythonhosted.org/packages/09/a1/2bc694313083cc46724ec26ff39fd04aaedd2ef7a9c748810af6d3021620/PyLTI1p3-1.3.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "40ca78935f5acc5d5312c15497f263d8", "sha256": "fadb860f4600b7f355435dbc5866445bd240a7df68740b45df3b2937d21cd7bb" }, "downloads": -1, "filename": "PyLTI1p3-1.3.0.tar.gz", "has_sig": false, "md5_digest": "40ca78935f5acc5d5312c15497f263d8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21419, "upload_time": "2019-08-22T13:18:01", "upload_time_iso_8601": "2019-08-22T13:18:01.689647Z", "url": "https://files.pythonhosted.org/packages/85/3e/e3b1f07bde3eaebc4482ac5889349a59bdddc8ec011a3fcc04f8aa4b94e4/PyLTI1p3-1.3.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.1": [ { "comment_text": "", "digests": { "md5": "7ecdf96045568875941896b299f6f57b", "sha256": "3e08763ccba7b3ef69479365465c7b3a05f96f1e0616a2abcb0cf7a82a6b218e" }, "downloads": -1, "filename": "PyLTI1p3-1.3.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "7ecdf96045568875941896b299f6f57b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25463, "upload_time": "2019-10-30T10:05:55", "upload_time_iso_8601": "2019-10-30T10:05:55.140604Z", "url": "https://files.pythonhosted.org/packages/7b/10/cf50c23d6fcd4dcd9a7c8cd6ee45b508d9ba94b68e1e0b0d9d3fe3e2f3ed/PyLTI1p3-1.3.1-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "3740aba19ac2ffbf4ac003e7e83d5be4", "sha256": "5659965c9c60f8d731f4227311f4020094df36ca8effa901ad84941a2f4f77f8" }, "downloads": -1, "filename": "PyLTI1p3-1.3.1.tar.gz", "has_sig": false, "md5_digest": "3740aba19ac2ffbf4ac003e7e83d5be4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21515, "upload_time": "2019-10-30T10:05:57", "upload_time_iso_8601": "2019-10-30T10:05:57.357950Z", "url": "https://files.pythonhosted.org/packages/29/b8/0e6c04be9c90358f4afb0c29e23e2a7ecbf5fec2829ce6c56f6383aeb3d4/PyLTI1p3-1.3.1.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.2": [ { "comment_text": "", "digests": { "md5": "83821f6f4aafd10122fd9c66e75dec3b", "sha256": "053989ac8285913d38d75f3eea5ff3731e9225ab22d63d430191792d999d23fc" }, "downloads": -1, "filename": "PyLTI1p3-1.3.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "83821f6f4aafd10122fd9c66e75dec3b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25479, "upload_time": "2019-10-30T10:34:06", "upload_time_iso_8601": "2019-10-30T10:34:06.702333Z", "url": "https://files.pythonhosted.org/packages/9a/f9/ea6fbaf3e91ea1f87ba1cdf8ded4747c772d51d95e5c077b0dc244b9df8b/PyLTI1p3-1.3.2-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "ed577d8090d9b6d252b0b414ac8a7cb3", "sha256": "7b7870c471a2ca786dcba579ba75ae319194f747d2a6f3ca6efab2b86aa4eff6" }, "downloads": -1, "filename": "PyLTI1p3-1.3.2.tar.gz", "has_sig": false, "md5_digest": "ed577d8090d9b6d252b0b414ac8a7cb3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21514, "upload_time": "2019-10-30T10:34:08", "upload_time_iso_8601": "2019-10-30T10:34:08.403606Z", "url": "https://files.pythonhosted.org/packages/23/b3/f63b3ed96f00e775cc1583897806c023885dcaae1eaf7cd1cb682264ca3b/PyLTI1p3-1.3.2.tar.gz", "yanked": false, "yanked_reason": null } ], "1.3.3": [ { "comment_text": "", "digests": { "md5": "9d5336c008f002857aa5644321d404cd", "sha256": "995a9771a3e48b5c46c8241252ce9d15ff4ef4f9b8d5918541c52a3bbd12841f" }, "downloads": -1, "filename": "PyLTI1p3-1.3.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "9d5336c008f002857aa5644321d404cd", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25484, "upload_time": "2020-01-23T10:31:14", "upload_time_iso_8601": "2020-01-23T10:31:14.209408Z", "url": "https://files.pythonhosted.org/packages/d3/51/8126534c71fe47137283e49f92f465c1de5d2e962b199a4780274c1aef95/PyLTI1p3-1.3.3-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "f038dd877ca8964049d4b9d19dacf7af", "sha256": "8ef27e67e9afde0b6f8d08c25054482a6a2da13c45ff18c58c89d38dc73b9443" }, "downloads": -1, "filename": "PyLTI1p3-1.3.3.tar.gz", "has_sig": false, "md5_digest": "f038dd877ca8964049d4b9d19dacf7af", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21527, "upload_time": "2020-01-23T10:31:16", "upload_time_iso_8601": "2020-01-23T10:31:16.240149Z", "url": "https://files.pythonhosted.org/packages/40/bc/e90020c26039a45c0a4af8e1b86a32dff34afcc0f58833a48044f1b3bb2c/PyLTI1p3-1.3.3.tar.gz", "yanked": false, "yanked_reason": null } ], "1.4.0": [ { "comment_text": "", "digests": { "md5": "6087b5aadeca03043ee1c6c1042d494e", "sha256": "0b3ca838009a8a3e4fde6f62971ebd6a73ae751053eab6eb9e1916abdfbd0830" }, "downloads": -1, "filename": "PyLTI1p3-1.4.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "6087b5aadeca03043ee1c6c1042d494e", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 29999, "upload_time": "2020-03-24T11:55:42", "upload_time_iso_8601": "2020-03-24T11:55:42.559317Z", "url": "https://files.pythonhosted.org/packages/b8/63/dedc6abf9837f825876e5c04867ac7dbd747883fd356a1e860fc97ceae69/PyLTI1p3-1.4.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "956711fc063cee0457d8d105e656516b", "sha256": "385af17d2deddddc80b9e9dc02739c0043bab0b042ae545cf62bf9dc7aa27cc9" }, "downloads": -1, "filename": "PyLTI1p3-1.4.0.tar.gz", "has_sig": false, "md5_digest": "956711fc063cee0457d8d105e656516b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19537, "upload_time": "2020-03-24T11:55:44", "upload_time_iso_8601": "2020-03-24T11:55:44.517359Z", "url": "https://files.pythonhosted.org/packages/00/00/9ee4f2f45e19275043d6d1be4b229878e7d42ffb63bce9fb9c4841b7755a/PyLTI1p3-1.4.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.5.0": [ { "comment_text": "", "digests": { "md5": "e943f1a474bf76bb7172947e36474a80", "sha256": "5ef312c43a6407cd57f835b39e8fd943c86e2331d00797c2feff739e5ea400b3" }, "downloads": -1, "filename": "PyLTI1p3-1.5.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e943f1a474bf76bb7172947e36474a80", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 40760, "upload_time": "2020-04-23T22:15:18", "upload_time_iso_8601": "2020-04-23T22:15:18.540501Z", "url": "https://files.pythonhosted.org/packages/ff/9d/b7fe10b06201b508b93df1549fe09606daf10edce1c96b938129f10a0523/PyLTI1p3-1.5.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "21e7c2585aadb1ce61504de6f58f465d", "sha256": "2f394f80c6a6a2065edb9513cee07dc3162cf7dbef0cd379d402b2f20d777fdb" }, "downloads": -1, "filename": "PyLTI1p3-1.5.0.tar.gz", "has_sig": false, "md5_digest": "21e7c2585aadb1ce61504de6f58f465d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27501, "upload_time": "2020-04-23T22:15:20", "upload_time_iso_8601": "2020-04-23T22:15:20.231234Z", "url": "https://files.pythonhosted.org/packages/bc/c0/8f7c7ffae95e1cee75608fb2b97de380bc1b27a9b03dfbacf448415b25c3/PyLTI1p3-1.5.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.6.0": [ { "comment_text": "", "digests": { "md5": "1d18b5a85a30103b84734aa645fe38b6", "sha256": "aca6f4938dda971852aeb5bc486a4e6a7d78250baa87610c3dd4842a10861abc" }, "downloads": -1, "filename": "PyLTI1p3-1.6.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "1d18b5a85a30103b84734aa645fe38b6", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 41389, "upload_time": "2020-04-30T13:52:07", "upload_time_iso_8601": "2020-04-30T13:52:07.155290Z", "url": "https://files.pythonhosted.org/packages/91/13/4d1b00465c7687c663ed309c16b6a136f63cbf23e69d250301806a836c32/PyLTI1p3-1.6.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "5cd2b4ac9d94051ee5bdab2e40db863a", "sha256": "538f92eccba5f0d2dc167ba35ad3bbca26888d8bbee77aa2e133654bc9d04fc2" }, "downloads": -1, "filename": "PyLTI1p3-1.6.0.tar.gz", "has_sig": false, "md5_digest": "5cd2b4ac9d94051ee5bdab2e40db863a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28065, "upload_time": "2020-04-30T13:52:09", "upload_time_iso_8601": "2020-04-30T13:52:09.303615Z", "url": "https://files.pythonhosted.org/packages/c9/c0/d3802678ee9e50619944b3d8f87da46962f990f308328aee2e8c223ada09/PyLTI1p3-1.6.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.6.1": [ { "comment_text": "", "digests": { "md5": "ab3c5c479906cc170a0630e2251c2b22", "sha256": "edc96567688a3e2d9827f9862778f68986231fb70c171625be289a4c1db45176" }, "downloads": -1, "filename": "PyLTI1p3-1.6.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "ab3c5c479906cc170a0630e2251c2b22", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 41405, "upload_time": "2020-05-01T21:16:28", "upload_time_iso_8601": "2020-05-01T21:16:28.030793Z", "url": "https://files.pythonhosted.org/packages/c0/6d/540c3ab5e82a4f3c303d58f5d7b9bce6c389889edc762e15173bfd56636a/PyLTI1p3-1.6.1-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "35b3dc6c8bdbdd06d11aa35db61a875f", "sha256": "4abde0d75d0681ca8d1b22fd57ab41540dacca75141087398792028106f7b6fc" }, "downloads": -1, "filename": "PyLTI1p3-1.6.1.tar.gz", "has_sig": false, "md5_digest": "35b3dc6c8bdbdd06d11aa35db61a875f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28044, "upload_time": "2020-05-01T21:16:29", "upload_time_iso_8601": "2020-05-01T21:16:29.722935Z", "url": "https://files.pythonhosted.org/packages/7b/71/cf55c1718033a89d83f4c2e94f0332fb4d410771561dbc6af92486ec0a27/PyLTI1p3-1.6.1.tar.gz", "yanked": false, "yanked_reason": null } ], "1.7.0": [ { "comment_text": "", "digests": { "md5": "bcaaf75668cb4bee5c70a2f3d7d8c863", "sha256": "9d203b25d83dc0e926d85c340272a443b7971fcbafdd7652430f5b9ae1a6da75" }, "downloads": -1, "filename": "PyLTI1p3-1.7.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "bcaaf75668cb4bee5c70a2f3d7d8c863", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 47760, "upload_time": "2020-05-04T17:30:16", "upload_time_iso_8601": "2020-05-04T17:30:16.513410Z", "url": "https://files.pythonhosted.org/packages/71/fb/4aa15823ac79d61aabf1fad7f471cf752493f2ffbf0b56394895cc693739/PyLTI1p3-1.7.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "cd76fabab68fc4ebcc296d7f09715baf", "sha256": "4409b325facd5d522099459ae2e5edd12f6f8e4ab2529a962720ca320592efcf" }, "downloads": -1, "filename": "PyLTI1p3-1.7.0.tar.gz", "has_sig": false, "md5_digest": "cd76fabab68fc4ebcc296d7f09715baf", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 32803, "upload_time": "2020-05-04T17:30:18", "upload_time_iso_8601": "2020-05-04T17:30:18.119029Z", "url": "https://files.pythonhosted.org/packages/a6/bc/2c1e4d31cbc7ecc3f14ee9ae4d6f9cb97d0f289614aaa391251980756e98/PyLTI1p3-1.7.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.8.0": [ { "comment_text": "", "digests": { "md5": "565aec6985643c5771a93280736645c1", "sha256": "a4c701153571929b0180bfa2916d87c72c457c75a719ade2f69527502bf4b3de" }, "downloads": -1, "filename": "PyLTI1p3-1.8.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "565aec6985643c5771a93280736645c1", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 55763, "upload_time": "2020-09-08T18:48:09", "upload_time_iso_8601": "2020-09-08T18:48:09.492355Z", "url": "https://files.pythonhosted.org/packages/23/c5/e2e163a03608e98ec325245aa510e8b520ab787c3e1486ebedaab3182346/PyLTI1p3-1.8.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "c2f0b294ab20b4722223b44129ba96ac", "sha256": "9ca7f6796085351ac80b39751340535ef23301aeda4fe73fcc3e19da6dbf4c51" }, "downloads": -1, "filename": "PyLTI1p3-1.8.0.tar.gz", "has_sig": false, "md5_digest": "c2f0b294ab20b4722223b44129ba96ac", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 38488, "upload_time": "2020-09-08T18:48:11", "upload_time_iso_8601": "2020-09-08T18:48:11.479646Z", "url": "https://files.pythonhosted.org/packages/02/5d/6d978d445597b40f3920a54619208eae9e168e0993cefb163184aa4de490/PyLTI1p3-1.8.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.8.1": [ { "comment_text": "", "digests": { "md5": "fada4d2fe39b970b5662ac84c7e0449f", "sha256": "4d066017c350cc15b5f3d833f96fe4dbeaa22c9adbd351f9ba5c0cad8ee3ba6d" }, "downloads": -1, "filename": "PyLTI1p3-1.8.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "fada4d2fe39b970b5662ac84c7e0449f", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 55762, "upload_time": "2020-09-08T21:00:49", "upload_time_iso_8601": "2020-09-08T21:00:49.756033Z", "url": "https://files.pythonhosted.org/packages/e2/45/a6ae9e96df9fde7b8af3cd9acba340e118c46e3fff5ffe6fa30725b09a6b/PyLTI1p3-1.8.1-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "e48b6f030ea49154f73a25ad3bfac792", "sha256": "04d5c6927fe5bb4b3e99d9b03292f9d15532224556917abf30b3cabb0cc15043" }, "downloads": -1, "filename": "PyLTI1p3-1.8.1.tar.gz", "has_sig": false, "md5_digest": "e48b6f030ea49154f73a25ad3bfac792", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 43698, "upload_time": "2020-09-08T21:00:52", "upload_time_iso_8601": "2020-09-08T21:00:52.051162Z", "url": "https://files.pythonhosted.org/packages/63/2d/7195c430a065be2157d54a4bda897769960051bd725f7a7fa8337560dcf3/PyLTI1p3-1.8.1.tar.gz", "yanked": false, "yanked_reason": null } ], "1.8.2": [ { "comment_text": "", "digests": { "md5": "cb713432a595b889b8db7c56b807a570", "sha256": "02b50db4d238b2f49ce043bf728e07b6a5a15d062e12a9506cdb880630f0f551" }, "downloads": -1, "filename": "PyLTI1p3-1.8.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "cb713432a595b889b8db7c56b807a570", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 55817, "upload_time": "2020-11-21T22:25:57", "upload_time_iso_8601": "2020-11-21T22:25:57.725648Z", "url": "https://files.pythonhosted.org/packages/1c/f0/c15ea9ea5e6e30a37d6d000e344afffbd626f3d54538229e6ada1e01f437/PyLTI1p3-1.8.2-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "93385114318c3389799de50dfb2e9135", "sha256": "19f734cdd83871dc6c61f5329e14f40bee6925453625583df36cfeee69a4b3cc" }, "downloads": -1, "filename": "PyLTI1p3-1.8.2.tar.gz", "has_sig": false, "md5_digest": "93385114318c3389799de50dfb2e9135", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 38561, "upload_time": "2020-11-21T22:25:59", "upload_time_iso_8601": "2020-11-21T22:25:59.808782Z", "url": "https://files.pythonhosted.org/packages/af/bd/24516293543d980ef0d0d787e67c8611d5af676d7c81f25bc93aeda8f237/PyLTI1p3-1.8.2.tar.gz", "yanked": false, "yanked_reason": null } ], "1.8.3": [ { "comment_text": "", "digests": { "md5": "91c79726a1705d068384b127f0f42a26", "sha256": "542f3cf1b19f3f6eff3adb2145e974ee2f932889e0591fbfa55e6006d83df866" }, "downloads": -1, "filename": "PyLTI1p3-1.8.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "91c79726a1705d068384b127f0f42a26", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 55837, "upload_time": "2020-11-24T11:54:55", "upload_time_iso_8601": "2020-11-24T11:54:55.734932Z", "url": "https://files.pythonhosted.org/packages/0c/bb/f4953d42c0474190444c0d7f17b5180b19660abfd26e748d770161a86495/PyLTI1p3-1.8.3-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "fc27438b57d4daa02101c1bd5be01fb0", "sha256": "427d6cf1fc288ee44f9e63b063d03a9d72116f4ca8f5bdc788b7652ceb4dd026" }, "downloads": -1, "filename": "PyLTI1p3-1.8.3.tar.gz", "has_sig": false, "md5_digest": "fc27438b57d4daa02101c1bd5be01fb0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 38593, "upload_time": "2020-11-24T11:54:57", "upload_time_iso_8601": "2020-11-24T11:54:57.905712Z", "url": "https://files.pythonhosted.org/packages/ca/1b/713f7360f3b962604b76413f32c48c6f2c0075a57b53f08e6ca80cba9aaf/PyLTI1p3-1.8.3.tar.gz", "yanked": false, "yanked_reason": null } ], "1.8.4": [ { "comment_text": "", "digests": { "md5": "7a0e52e7f7a3b942f0eebaba7f5dc676", "sha256": "e8783cf1e547d8e472a46f08423591c00d5ecaa7de181c1c84d2628e983d0f94" }, "downloads": -1, "filename": "PyLTI1p3-1.8.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "7a0e52e7f7a3b942f0eebaba7f5dc676", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 55908, "upload_time": "2021-01-17T23:00:44", "upload_time_iso_8601": "2021-01-17T23:00:44.748861Z", "url": "https://files.pythonhosted.org/packages/c7/7a/055617222ffcaf6f6aefbe2bdc0b677526a5d434bccca874ed2e2ae17576/PyLTI1p3-1.8.4-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "6fd3c09220acdec558e3fa0442ec7fe4", "sha256": "d1fbc1444fe18caf02543321561bda8e4a82103025ff4054aae59d6eb3be11f3" }, "downloads": -1, "filename": "PyLTI1p3-1.8.4.tar.gz", "has_sig": false, "md5_digest": "6fd3c09220acdec558e3fa0442ec7fe4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 38677, "upload_time": "2021-01-17T23:00:46", "upload_time_iso_8601": "2021-01-17T23:00:46.922097Z", "url": "https://files.pythonhosted.org/packages/85/07/1624271a4d3df556579c4b509495d1e3015ab63b9cc2692a9d6d777bee56/PyLTI1p3-1.8.4.tar.gz", "yanked": false, "yanked_reason": null } ], "1.8.5": [ { "comment_text": "", "digests": { "md5": "dd9ac4a1074b3bf69931ca1101d60355", "sha256": "f71642cb81eb3ca7a1933682574e76e95db16bc793dbf7b834c2efed1ff163ac" }, "downloads": -1, "filename": "PyLTI1p3-1.8.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "dd9ac4a1074b3bf69931ca1101d60355", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 56068, "upload_time": "2021-02-16T14:45:05", "upload_time_iso_8601": "2021-02-16T14:45:05.978268Z", "url": "https://files.pythonhosted.org/packages/87/13/c9ba2947e3249284fc45378110ec112d0a918bf15f1a4d1efd58c8e7f131/PyLTI1p3-1.8.5-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "fb54c6b4b62ccb0ad05707172e4524d4", "sha256": "297bd705bb7290b0544e94c64f89979a9742165cede2c9f548758d6217cf4685" }, "downloads": -1, "filename": "PyLTI1p3-1.8.5.tar.gz", "has_sig": false, "md5_digest": "fb54c6b4b62ccb0ad05707172e4524d4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 38734, "upload_time": "2021-02-16T14:45:08", "upload_time_iso_8601": "2021-02-16T14:45:08.186674Z", "url": "https://files.pythonhosted.org/packages/85/56/ceb4686176f8d62073e95c85666043d9a71f395806d17efc93f00130673b/PyLTI1p3-1.8.5.tar.gz", "yanked": false, "yanked_reason": null } ], "1.8.6": [ { "comment_text": "", "digests": { "md5": "8e4d6455f1d6caf21b0d4d29352c302c", "sha256": "6702e50da562c3dcd5b509ee2483935c6f0b623ca3b343abb5fd976642ba630a" }, "downloads": -1, "filename": "PyLTI1p3-1.8.6-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "8e4d6455f1d6caf21b0d4d29352c302c", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 56635, "upload_time": "2021-04-09T22:09:43", "upload_time_iso_8601": "2021-04-09T22:09:43.827475Z", "url": "https://files.pythonhosted.org/packages/99/6f/a62c680895d0303b6d12a210e4f3b24ce1a0478abb31da1404523fb28190/PyLTI1p3-1.8.6-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "607b8c13a2b7443992656b2023eebbe9", "sha256": "1602503eaa7c40b38ff39076c2008337ade67219da1bd70751dbd6052782788e" }, "downloads": -1, "filename": "PyLTI1p3-1.8.6.tar.gz", "has_sig": false, "md5_digest": "607b8c13a2b7443992656b2023eebbe9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 39252, "upload_time": "2021-04-09T22:09:46", "upload_time_iso_8601": "2021-04-09T22:09:46.036352Z", "url": "https://files.pythonhosted.org/packages/ec/54/b44c6440b65ff43d086ab491b38731fc62c4d775093247a153a629c0de6c/PyLTI1p3-1.8.6.tar.gz", "yanked": false, "yanked_reason": null } ], "1.8.7": [ { "comment_text": "", "digests": { "md5": "7e3a9bce652e77b881edcb0a69e23aca", "sha256": "a1c413addfb89cc2df5e5e88ab3da60f89ebfc03051c490d21f54ebe67143dd2" }, "downloads": -1, "filename": "PyLTI1p3-1.8.7-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "7e3a9bce652e77b881edcb0a69e23aca", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 56704, "upload_time": "2021-04-26T13:05:45", "upload_time_iso_8601": "2021-04-26T13:05:45.312872Z", "url": "https://files.pythonhosted.org/packages/dc/0c/43c20597446c713d75f110da505f21de4488ca1c57478e3fc9a658963774/PyLTI1p3-1.8.7-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "74725457b9f2c36b63f2800c22069582", "sha256": "8e2127e500880579d2c04c0656466e9641efd3761289f97b97f11857bdf7fc83" }, "downloads": -1, "filename": "PyLTI1p3-1.8.7.tar.gz", "has_sig": false, "md5_digest": "74725457b9f2c36b63f2800c22069582", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 39320, "upload_time": "2021-04-26T13:05:47", "upload_time_iso_8601": "2021-04-26T13:05:47.053863Z", "url": "https://files.pythonhosted.org/packages/9b/24/116556da48b2b4d8fbbeaf96e365ebadf7e5891515db0061d09fc2e6a71c/PyLTI1p3-1.8.7.tar.gz", "yanked": false, "yanked_reason": null } ], "1.9.0": [ { "comment_text": "", "digests": { "md5": "d46cd92bfb10e59ea386cf4c51bf2276", "sha256": "26a3eeee7dca61c5c222e0bfc8916be53542cbb17cb3326fa131fbe87b812599" }, "downloads": -1, "filename": "PyLTI1p3-1.9.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "d46cd92bfb10e59ea386cf4c51bf2276", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 57776, "upload_time": "2021-05-12T10:36:00", "upload_time_iso_8601": "2021-05-12T10:36:00.070787Z", "url": "https://files.pythonhosted.org/packages/7e/e7/6b9b941ed50952da6521ea09b053d46812e4dd10c3252ea2ad94ca3c4fc3/PyLTI1p3-1.9.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "15033149d71554da66ded5e31a337867", "sha256": "b8954b03ed0388a4d144ca9ff64255755dad6373e474c24bc30b50737e2045e1" }, "downloads": -1, "filename": "PyLTI1p3-1.9.0.tar.gz", "has_sig": false, "md5_digest": "15033149d71554da66ded5e31a337867", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 45402, "upload_time": "2021-05-12T10:36:02", "upload_time_iso_8601": "2021-05-12T10:36:02.378269Z", "url": "https://files.pythonhosted.org/packages/71/4a/2eedb6b6d5e9d3be7c627e2ed48423497ae10089be21e14bbe44d28c08a2/PyLTI1p3-1.9.0.tar.gz", "yanked": false, "yanked_reason": null } ], "1.9.1": [ { "comment_text": "", "digests": { "md5": "6d948261bb75967bb6266e1596662009", "sha256": "be3c01a222f0c678f7f50bba4a91a9f537fe64255eeb2c0e246b09a78b0018ed" }, "downloads": -1, "filename": "PyLTI1p3-1.9.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "6d948261bb75967bb6266e1596662009", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 58673, "upload_time": "2021-05-24T15:36:19", "upload_time_iso_8601": "2021-05-24T15:36:19.494649Z", "url": "https://files.pythonhosted.org/packages/a3/58/f455b58745f48e3ad9c6cf563e5f014d0f7be3647abc417ccdbfa19098f6/PyLTI1p3-1.9.1-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "99a55f5c01536db331f7664494f3999a", "sha256": "eca23091699a28c7209f1cacad117f5f800bf95f980d30cd44b2fd1f6553a116" }, "downloads": -1, "filename": "PyLTI1p3-1.9.1.tar.gz", "has_sig": false, "md5_digest": "99a55f5c01536db331f7664494f3999a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 42042, "upload_time": "2021-05-24T15:36:21", "upload_time_iso_8601": "2021-05-24T15:36:21.748421Z", "url": "https://files.pythonhosted.org/packages/23/2e/b7d1156109ddf0ced79d7b8fdde7c310e6539743050f950455f4fc672139/PyLTI1p3-1.9.1.tar.gz", "yanked": false, "yanked_reason": null } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "04b1aa26a598fc7c25eb0e92b2614efd", "sha256": "3525c46310cf42a10c4c221c6539f66ed0953b843caec6f50ad6944d84978587" }, "downloads": -1, "filename": "PyLTI1p3-1.11.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "04b1aa26a598fc7c25eb0e92b2614efd", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 62121, "upload_time": "2022-04-21T15:01:16", "upload_time_iso_8601": "2022-04-21T15:01:16.613409Z", "url": "https://files.pythonhosted.org/packages/c9/bc/90fc6fa6fd8bfeaaae7086d4f3af68074530d5b1a528a46b6506fd350f5c/PyLTI1p3-1.11.0-py2.py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "ea29a7c64e2acc5adaacaf2c30ba9de3", "sha256": "4d029715b67158f7746aec4f42d0abf8221c037b3923e9aacfae888a1095647a" }, "downloads": -1, "filename": "PyLTI1p3-1.11.0.tar.gz", "has_sig": false, "md5_digest": "ea29a7c64e2acc5adaacaf2c30ba9de3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 46244, "upload_time": "2022-04-21T15:01:21", "upload_time_iso_8601": "2022-04-21T15:01:21.602594Z", "url": "https://files.pythonhosted.org/packages/c7/f8/6617d26cd0dccfbd5782438b1ac1a1e83326bb7ddf01bec7df8618b22655/PyLTI1p3-1.11.0.tar.gz", "yanked": false, "yanked_reason": null } ], "vulnerabilities": [] }