{ "info": { "author": "Alistair O'Brien", "author_email": "alistair@duneroot.co.uk", "bugtrack_url": null, "classifiers": [], "description": "# AppSync - Gremlin\n\n## Overview\n\nThrough the AppSync-Gremlin, developers can write powerful queries in GraphQL without having to worry\ntoo much about the underlying database query language in AWS Neptune. The AppSync-Gremlin provides\nlambda function code that converts query operation types (from GraphQL) to a gremlin traversal.\n\n## Definitions\n\n\n- **Property field**: A field corresponding to a property of a vertex in the AWS Neptune graph database. In the below example,\n the `name` field is a property field.\n ```\n {\n User {\n name\n following {\n name\n }\n }\n }\n ```\n > Query 1 : (Vertex Field Example)\n\n- **Vertex field**: A field corresponding to a vertex in the AWS Neptune graph database. In the above example,\n `location` is a vertex field.\n\n- **Vertex list fields**: A field corresponding to a list of vertices in the AWS Neptune graph database. In the above example,\n `following` is a vertex list field.\n\n- **Result set**: An assignment of vertices in the graph to fields in the query. As the database processes the query, new\n result sets may be created (e.g. when traversing edges), and result sets may be discarded when they do not satisfy filters.\n After all parts of the query are processed by the database, all remaining result sets are used to form the query result, by taking their values at all\n properties marked for output (anything in an output scope).\n\n- **Scope**: The part of a query between any pair of parentheses or curly braces. We often refer to the parts between parentheses as the\n *input scope* and the parts between curly braces as the *output scope* or *payload scope*.\n For example, consider the query\n ```\n {\n User (\n input: {\n name: {\n eq: \"John\"\n }\n }\n ) {\n name\n following {\n name\n }\n }\n }\n ```\n > Query 2 : (Scope Example)\n\n## Filtering Operations and Pagination\n\n\n### Filtering\n\nWe define a filtering standard on the following scalar fields:\n\n- **ID**:\n For ID filtering we define the following input for filtering:\n ```\n input IDFilterInput {\n ne: ID\n eq: ID\n\n in: [ID!]\n not_in: [ID!]\n }\n ```\n- **String**: For String filtering we define the following input for filtering\n ```\n input StringFilterInput {\n ne: String\n eq: String\n\n in: [String!]\n not_in: [String!]\n\n contains: String\n not_contains: String\n\n begins_with: String\n not_begins_with: String\n\n ends_with: String\n not_ends_with: String\n }\n ```\n- **Int**: For Integer filtering we define the following input for filtering\n ```\n input IntFilterInput {\n ne: Int\n eq: Int\n le: Int\n lt: Int\n ge: Int\n gt: Int\n\n in: [Int!]\n not_in: [int!]\n }\n ```\n- **Float**: For Float filtering we define the following input for filtering\n ```\n input FloatFilterInput {\n ne: Float\n eq: Float\n le: Float\n lt: Float\n ge: Float\n gt: Float\n\n in: [Float!]\n not_in: [Float!]\n }\n ```\n- **Boolean**: For Boolean filtering we define the following input for filtering\n ```\n input BooleanFilterInput {\n eq: Boolean\n ne: Boolean\n }\n ```\n- **DateTime**: For DateTime we first have to define our own DateTime input definition. To avoid confusion and to prevent the use of different DateTime formats\n in this interface, we have defined the following `DateTimeInput` to expose the individual date components (such as day, month, year, etc) as well\n as a `formatted` field which is the ISO 8601 string representation of the DateTime value:\n ```\n input DateTimeInput {\n year: Int\n month: Int\n day: Int\n hour: Int\n minute: Int\n second: Int\n formatted: DateTime #custom datetime scalar\n }\n ```\n Using this input definition, we can then create the following input for filtering:\n ```\n input DateTimeFilterInput {\n eq: DateTimeInput\n ne: DateTimeInput\n\n in: [DateTimeInput!]\n not_in: [DateTimeInput!]\n\n le: DateTimeInput\n lt: DateTimeInput\n ge: DateTimeInput\n gt: DateTimeInput\n }\n ```\n\nand a filtering standard on enum types:\n```\nenum ENUM_FIELD_TYPE {\n E_1\n E_2\n .\n .\n .\n E_n\n}\n\ninput EnumFilterInput {\n eq: ENUM_FIELD_TYPE\n ne: ENUM_FIELD_TYPE\n in: [ENUM_FIELD_TYPE!]\n not_in: [ENUM_FIELD_TYPE!]\n}\n```\n\nNote that these standards must be manually implemented in the original GraphQL schema. In future we may devise some method of augmenting a GraphQL schema\nso we don't have to manually implement them.\n\nEach of these scalar filters has a corresponding filter in the AppSync-Gremlin library. For example, the `StringFilterInput` has\nthe scalar filter `string_filter`, etc.\n\n#### Implementing Filters\n\nThe AppSync-Gremlin library also allows custom `vertex`, `relationship` and `scalar` filters to be implemented.\n\n- **Scalar filters**: We define a `scalar` filter as a filter that maps GraphQL fields to Gremlin predicates. Consider an `id_filter`. \n In GraphQL, the `IDFilterInput` has the following fields: `eq, ne, in, not_in`. The Gremlin predicates that correspond to these fields are \n `eq, neq, within, without`. So we construct the following dictionary to map the GraphQL fields to the Gremlin predicates:\n ```python\n from gremlin_python.process.traversal import eq, neq, within, without\n\n def id_scalar_filter():\n return {\n \"eq\": eq,\n \"ne\": neq,\n \"in\": within,\n \"not_in\": without\n }\n ```\n By using this dictionary, we can construct a filter function that applies the predicates to some traversal `g`, such that the traverser is \n at some vertices `v` with property `property_name`, \n producing a filtered traversal with the general form ,\n\n `g' = g.has(property_name, p_1).has(property_name, p_2). ... .has(property_name, p_n)`,\n\n where `p_1, p_2, ..., p_n` are predicates that are applied to the property `property_name` at `v`. \n\n The `@scalar_filter` decorator provided by the AppSync-Gremlin library produces a function that takes a `property_name`\n and returns the function described above. So by applying this to the above `id_filter` gives us\n ```python\n from gremlin_python.process.traversal import eq, neq, within, without\n from appsync_gremlin import scalar_filter\n\n @scalar_filter\n def id__filter():\n return {\n \"eq\": eq,\n \"ne\": neq,\n \"in\": within,\n \"not_in\": without\n }\n ```\n However, at this stage the filter cannot actually be used, since it requires a `property_name`. The AppSync-Gremlin library\n provides two different ways of applying a `property_name` to a filter. Either we can simply call `id_scalar_filter`\n with out desired `property_name`, or we can apply the `@name` decorator. \n\n For scalar filters, we advice that the former is used. Since this provides a better generalisation for your scalar filter. \n Since a vertex could implement it's own custom id with property name `\"id\"` or simply make use of the built in vertex id\n `T.id`. \n\n- **Vertex filter**: We define a `vertex` filter as a filter that maps GraphQL fields to `scalar` or `relationship` (see below) filters.\n Let us consider the following GraphQL `User` type:\n ```\n type User {\n id: ID!\n email: String!\n\n name: String\n about: String\n\n following: [User]!\n followed_by: [User]!\n }\n ```\n We have 4 scalar fields (`id, email, name, about`) and 2 vertex list fields (`following, followed_by`). In the Graph database, we define \n a `User` vertex with properties `email, name, about` (string) and a single relationship `User -> FOLLOWS -> User`. So in a similar fashion to \n a scalar filter, let us define some function that returns a dictionary mapping the GraphQL fields to filters:\n ```python\n from gremlin_python.process.traversal import T \n from appsync_gremlin import id_filter, string_filter\n\n def user_filter():\n return {\n \"id\": id_filter(T.id),\n \"email\": string_filter(\"email\"),\n \"name\": string_filter(\"name\"),\n \"about\": string_filter(\"about\"),\n \"following\": ?,\n \"followed_by\": ?\n }\n ```\n By using this dictionary we can construct a filter function that applies the `scalar` and `relationship` filters to some \n supplied traversal `g`, such that the traverser is at some vertices `v` which matches the desired filter (in this case the travesers must all be at `User` vertices),\n producing a filtered traversal `g'` with the general form:\n\n g' = r_1(r_2( ... (r_n(s_1( ... s_m(g) ... ))) ... ))\n\n where `r_1, r_2, ..., r_n` are relationship filters and `s_1, s_2, ..., s_m` are scalar filters. Note that the order of application of scalar and relationship\n filters does not matter, however, we advice that scalar filters should be applied first as it is more efficient. \n\n The `@vertex_filter` decorator provided by the AppSync-Gremlin library produces a function that takes a `vertex_label`\n and returns the function described above. So by applying this to the above `user_filter` gives us\n ```python\n from gremlin_python.process.traversal import T\n from appsync_gremlin import id_filter, string_filter, vertex_filter, name\n\n @name(\"User\")\n @vertex_filter\n def user_filter():\n return {\n \"id\": id_filter(T.id),\n \"email\": string_filter(\"email\"),\n \"name\": string_filter(\"name\"),\n \"about\": string_filter(\"about\"),\n \"following\": ?,\n \"followed_by\": ?\n }\n ```\n Similarly to the `scalar_filter`, we can apply the `@name` decorator to pass the `vertex_label` to the filter function. \n This label should match the label of the `User` vertex in the Graph database.\n\n With the vertex filter now completely implemented, we can now define our relationship filters (see below). In this case \n we have the relationship filters:\n ```python\n from gremlin_python.process.traversal import T \n from appsync_gremlin import id_filter, string_filter, vertex_filter, name, relationship_filter, RelationshipDirection\n\n @name(\"User\")\n @vertex_filter\n def user_filter():\n return {\n \"id\": id_filter(T.id),\n \"email\": string_filter(\"email\"),\n \"name\": string_filter(\"name\"),\n \"about\": string_filter(\"about\"),\n \"following\": relationship_filter((\"FOLLOWS\", RelationshipDirection.OUT), user_filter),\n \"followed_by\": relationship_filter((\"FOLLOWS\", RelationshipDirection.IN), user_filter)\n }\n ```\n\n- **Relationship filter**: We define a relationship `R` from some vertex `u` to `v` as `R = (name, direction)`. We can \n filter `u` based on the whether a relationship `R` exists and whether `v` satisfies certain conditions. \n\n Consider a Gremlin traversal `g`, such that the traverser is at some vertices `u`. We can produce a filtered traversal\n `g'` based on whether the vertices selected by `g` have the relationship `R` and the vertices `v` (the other vertex in `R`) satisfy\n a vertex filter `v_f`. This filtered traversal has the general form:\n\n g' = g.where(v_f(direction(name))).\n\n The AppSync-Gremlin library produces a function `relationship_filter` that takes a `relationship`, a tuple consisting of a \n edge label (`name`) and a edge direction (`direction`), and a vertex filter `v_f` for the other vertex in the relationship. \n\n (See above for example). \n\n\n### Pagination\n\nWe also implement a pagination standard. Note that pagination can only be applied to vertex list fields. \n\n For simplicity, we've decided to implement an offset based pagination, as it allows us to make us\nof the Gremlin traversal step `.range(first, offset)`. The stanardised pagination input is defined as follows:\n```\ninput PaginationInput {\n page: Int!\n per_page: Int!\n}\n```\nWe then use `page` and `per_page` to compute `first` and `offset` using the function `get_range`, shown below.\n```python\nfrom typing import Tuple\n\ndef get_range(page: int, per_page: int) -> Tuple[int, int]:\n \"\"\"\n Returns the Gremlin range from page options in the format:\n (first, last)\n\n :param page: (Integer)\n :param per_page: (Integer)\n :return: (Integer, Integer)\n \"\"\"\n\n return (page - 1) * per_page, page * per_page\n```\n\nOnce the traversal has been submitted and the result set has been return, we format the response into a pagination\nresponse object. The GraphQL type for this response object for some GraphQL type `Type` is\n```\ntype Type {\n .\n .\n .\n}\n\ntype TypePage {\n data: [Type]!\n page: Int!\n per_page: Int!\n total: Int!\n}\n```\nwhere `total` is the `total` number of pages available.\n\n## Error Handling and Request / Response Mapping Template\n\nThe AppSync-Gremlin library provides automatic error handling for AppSync. The library does this via the user of the `AppSyncException`.\nThe `AppSyncException` requires 3 arguments when instantiated: `error_type`, `error_message` and `error_data` for type\n string, string and dictionary respectively.\n\nFor example, consider the mutation resolver that creates a `User` vertex. Naturally we want to ensure that a user doesn't have a duplicate vertex,\ntherefore we must add some form of validation within the resolver code which raises an `AppSyncException` with the relevant error information\nif the validation fails.\n\n```python\nfrom gremlin_python.process.graph_traversal import GraphTraversal\nfrom appsync_gremlin import ResolverInput, AppSyncException, mutation_resolver\n\n@mutation_resolver\ndef create_user(traversal: GraphTraversal, resolver_input: ResolverInput) -> GraphTraversal:\n\n username = resolver_input.arguments.get(\"username\")\n user = traversal.V().hasLabel(\"User\").has(\"username\", username)\n\n if user.hasNext():\n raise AppSyncException(\n error_type=\"BAD_REQUEST\",\n error_message=\"A user with username {} is already stored in the AWS Neptune database.\".format(username),\n error_data={\n \"username\": username\n }\n )\n\n .\n .\n .\n```\n\nIn order to ensure our `AppSyncException` work's with AppSync, we've had to define a request / response template mapping standard.\nFor all resolvers, we must have the request template mapping:\n```\n{\n \"version\" : \"2018-05-29\",\n \"operation\": \"(Invoke|BatchInvoke)\",\n \"payload\": {\n \"type_name\": String!,\n \"field_name\": String!,\n \"arguments\": $util.toJson($context.args),\n \"identity\": $util.toJson($context.identity),\n \"source\": $util.toJson($context.source)\n }\n}\n```\nand the response mapping template:\n```\n#if ($context.result && $context.result.error)\n $utils.error($context.result.error.error_message, $context.result.error.error_type, $context.result.error.data)\n#else\n $utils.toJson($context.result.data)\n#end\n```\n\n### Usage\n\nThe AppSync-Gremlin library currently provides 4 different resolver types in the form of function decorators:\n- `vertex_list_field_resolver`\n- `vertex_field_resolver`\n- `calculated_field_resolver`\n- `mutation_resolver`\n\nThe first 3 resolvers are Query based resolvers, that is to say they are designed to be used for resolving GraphQL\nqueries. \n\nEach resolver has the same function type signature:\n\n resolver : (GraphTraversal, ResolverInput) -> GraphTraversal\n\nNote the custom `ResolverInput` object. A `ResolverInput` object simply stores the data passed from the Apache VTL \nrequest mapping template described in the section above. Hence the `ResolverInput` object has the following properties:\n - `type_name`: `(String)`\n - `field_name`: `(String)`\n - `arguments`: `(Dictionary)`\n - `identity` : `(Dictionary | None)`\n - `source`: `(Dictionary | None)`\n\nHence these properties can be referenced in the resolvers to build the Gremlin traversals. \n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "appsync-gremlin", "package_url": "https://pypi.org/project/appsync-gremlin/", "platform": "", "project_url": "https://pypi.org/project/appsync-gremlin/", "project_urls": null, "release_url": "https://pypi.org/project/appsync-gremlin/0.0.19/", "requires_dist": [ "gremlinpython" ], "requires_python": "", "summary": "A simple Python interface for AppSync resolvers and Gremlin traversals.", "version": "0.0.19" }, "last_serial": 5972176, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "68b1a83438251685335a1046b6b6acf1", "sha256": "879d9c6fe6312d7b9647b4d294fa0a3891132c10629486261f9f98b4d875dc4a" }, "downloads": -1, "filename": "appsync_gremlin-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "68b1a83438251685335a1046b6b6acf1", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7362, "upload_time": "2019-09-18T12:13:23", "url": "https://files.pythonhosted.org/packages/ec/03/d8f3aaabd1e2272d839ec0361a33bf3babc5b02e220c2e9e4d5e5458dd03/appsync_gremlin-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f091885adad6e88cad6665a951c1d730", "sha256": "58f1d72834fca62f82e26aed17cbec2c01984769564dbe1b4900744146ca81e3" }, "downloads": -1, "filename": "appsync-gremlin-0.0.1.tar.gz", "has_sig": false, "md5_digest": "f091885adad6e88cad6665a951c1d730", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5614, "upload_time": "2019-09-18T12:13:25", "url": "https://files.pythonhosted.org/packages/5c/e7/6fa2a34def4e65bb18a13caa0161cf5ccd859f6b549ba3993d8759314884/appsync-gremlin-0.0.1.tar.gz" } ], "0.0.10": [ { "comment_text": "", "digests": { "md5": "e193265e629b4201bb35b0e6aa477bd8", "sha256": "35e031d310d531d384f9bd8704da9b56bbd4a1fb423c3ff7411061c55b2e0150" }, "downloads": -1, "filename": "appsync_gremlin-0.0.10-py3-none-any.whl", "has_sig": false, "md5_digest": "e193265e629b4201bb35b0e6aa477bd8", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 11119, "upload_time": "2019-09-20T14:34:45", "url": "https://files.pythonhosted.org/packages/bd/2a/b64811a077c78f15da8f637f0aa03eaa4153eaa322d11ce5f37b8dddb46e/appsync_gremlin-0.0.10-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "17093d7ca1e124b674de3f22fdb02cb8", "sha256": "109e88fdca9a7cedaf875648824579a67545c563f68aded6c6b5616a4f539477" }, "downloads": -1, "filename": "appsync-gremlin-0.0.10.tar.gz", "has_sig": false, "md5_digest": "17093d7ca1e124b674de3f22fdb02cb8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8249, "upload_time": "2019-09-20T14:34:47", "url": "https://files.pythonhosted.org/packages/f8/49/fcdb0e9460459d7a9bc1cc53131ce2b10890c27060d1174c4f899e6e0dc7/appsync-gremlin-0.0.10.tar.gz" } ], "0.0.11": [ { "comment_text": "", "digests": { "md5": "a5743c3e8de21714f656ecc850984ae8", "sha256": "e2dd9437342943804fe584a972148dc8a51d51f32c010aed3475d05da420e565" }, "downloads": -1, "filename": "appsync_gremlin-0.0.11-py3-none-any.whl", "has_sig": false, "md5_digest": "a5743c3e8de21714f656ecc850984ae8", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 14092, "upload_time": "2019-09-22T15:33:10", "url": "https://files.pythonhosted.org/packages/eb/37/372d085dc5312690f60c3cace0b1108005157bef348aa3b1da4c7c06cde5/appsync_gremlin-0.0.11-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "70afe531e8615d617210e6a317246570", "sha256": "7fc9c71a59378f8d2eb8431a69059001613097084bc8c313968e059abc56064b" }, "downloads": -1, "filename": "appsync-gremlin-0.0.11.tar.gz", "has_sig": false, "md5_digest": "70afe531e8615d617210e6a317246570", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8260, "upload_time": "2019-09-22T15:33:11", "url": "https://files.pythonhosted.org/packages/6a/89/21d288c38c2a50c00ea0c5e52d228cd6a971283c22f7c186edf99ed45351/appsync-gremlin-0.0.11.tar.gz" } ], "0.0.12": [ { "comment_text": "", "digests": { "md5": "cae2ec3f3b7f4ae6f2b84e81aa709523", "sha256": "20744789d59f912e184fa5ba565f8345091fddfabb6b1300da2757d9f5151884" }, "downloads": -1, "filename": "appsync_gremlin-0.0.12-py3-none-any.whl", "has_sig": false, "md5_digest": "cae2ec3f3b7f4ae6f2b84e81aa709523", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 14101, "upload_time": "2019-09-22T15:36:54", "url": "https://files.pythonhosted.org/packages/4b/e5/5d86716a5afefec3ad2214ec475c641cd103d93464dd6f7593bdc002e307/appsync_gremlin-0.0.12-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "66bd5985bb01e62f9f7d82d3e87b8a06", "sha256": "fc82ba1f500b195bb0f95e8a1d4ca3b96194ab18a5a23a65ecfd1328669b8bd8" }, "downloads": -1, "filename": "appsync-gremlin-0.0.12.tar.gz", "has_sig": false, "md5_digest": "66bd5985bb01e62f9f7d82d3e87b8a06", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8263, "upload_time": "2019-09-22T15:36:55", "url": "https://files.pythonhosted.org/packages/65/da/7f9a055566ae7ad5e3902642ff88d5e7f1362f9e8891e80403943dcd6499/appsync-gremlin-0.0.12.tar.gz" } ], "0.0.13": [ { "comment_text": "", "digests": { "md5": "93565b481e8b795b9834a022e8e96f30", "sha256": "04212059f0e0039b046a6e62fea5fbdfdda309041434d3b0ce6944aeb57a43b3" }, "downloads": -1, "filename": "appsync_gremlin-0.0.13-py3-none-any.whl", "has_sig": false, "md5_digest": "93565b481e8b795b9834a022e8e96f30", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 14438, "upload_time": "2019-09-24T11:00:12", "url": "https://files.pythonhosted.org/packages/6f/e0/561697a510e817ea5d7376538b55a783d193c3716a84e3244403399b5779/appsync_gremlin-0.0.13-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "590683eec5b3b23ed9290c770927aa23", "sha256": "1cd3745b9acdd128048a69cde6a8e83f35d3642e58d586f65c85dd2dd4734be6" }, "downloads": -1, "filename": "appsync-gremlin-0.0.13.tar.gz", "has_sig": false, "md5_digest": "590683eec5b3b23ed9290c770927aa23", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8504, "upload_time": "2019-09-24T11:00:14", "url": "https://files.pythonhosted.org/packages/ed/9c/126c6adbff866cfd1364a66ec9c3e000172fbc998acb254ee202a9aab17d/appsync-gremlin-0.0.13.tar.gz" } ], "0.0.14": [ { "comment_text": "", "digests": { "md5": "82af258c7e877e782df8232ccdd63760", "sha256": "e5b219c8eced74385f26d0a2ccc8ea97085420a5834eb8e56a34eeff6f5d1507" }, "downloads": -1, "filename": "appsync_gremlin-0.0.14-py3-none-any.whl", "has_sig": false, "md5_digest": "82af258c7e877e782df8232ccdd63760", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 14453, "upload_time": "2019-09-24T11:02:07", "url": "https://files.pythonhosted.org/packages/60/89/a470313afbf529612a64df6ac3f3f2b54eff025639ab8a3512d3755f5aa8/appsync_gremlin-0.0.14-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "dea43b4ab5aacec04ff9c79010034249", "sha256": "4fdfc9bf5bc1116156cb6381b042c51a43eefd520468ad4b15cbb171df3f8ea2" }, "downloads": -1, "filename": "appsync-gremlin-0.0.14.tar.gz", "has_sig": false, "md5_digest": "dea43b4ab5aacec04ff9c79010034249", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8503, "upload_time": "2019-09-24T11:02:08", "url": "https://files.pythonhosted.org/packages/ee/9c/e657acee7289ad54e872b06ee04d46943e09f62a9976796f19a5fcac873f/appsync-gremlin-0.0.14.tar.gz" } ], "0.0.15": [ { "comment_text": "", "digests": { "md5": "86a7691428273379f13d172aaa514252", "sha256": "6faf9d6f68a32ac19171dd1b31c11f94266adb462a0327c938a327d5cdf80203" }, "downloads": -1, "filename": "appsync_gremlin-0.0.15-py3-none-any.whl", "has_sig": false, "md5_digest": "86a7691428273379f13d172aaa514252", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 15854, "upload_time": "2019-09-26T09:42:03", "url": "https://files.pythonhosted.org/packages/cc/2c/7d753036ce0166da9ef0ccd0342a0b541667469f50f74e3f463e491f35b3/appsync_gremlin-0.0.15-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ebbe07e72826ba989937b3b6e734c726", "sha256": "3b45629ffdf409c7a5fb0b22599b3475eebe5d0f471d3a8e07948a59d8cda34d" }, "downloads": -1, "filename": "appsync-gremlin-0.0.15.tar.gz", "has_sig": false, "md5_digest": "ebbe07e72826ba989937b3b6e734c726", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10016, "upload_time": "2019-09-26T09:42:05", "url": "https://files.pythonhosted.org/packages/6d/5d/ebe4ac744cdf7d49bac1761d6a8b58f1349a6e5c8d09c808bb6a307c750f/appsync-gremlin-0.0.15.tar.gz" } ], "0.0.16": [ { "comment_text": "", "digests": { "md5": "5cfe0d62a8e84ad909aa8b3115d9b2b0", "sha256": "8fcfffd7e0a86a8a93df663417479f0fd746832aefcc93f9550d0efc0d62aacc" }, "downloads": -1, "filename": "appsync_gremlin-0.0.16-py3-none-any.whl", "has_sig": false, "md5_digest": "5cfe0d62a8e84ad909aa8b3115d9b2b0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 15860, "upload_time": "2019-09-26T10:36:26", "url": "https://files.pythonhosted.org/packages/ba/db/9f3eefb272daa7a4bd351ad93f9d46b82b2a56fa35eaced4a1dc44928c60/appsync_gremlin-0.0.16-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8bd27342ac60619a07eb48c95b7a245d", "sha256": "4fcbe5f19975e8c397017f7e65bb34f4b7e3c4c1c669f56d8a9d28162ce5e50a" }, "downloads": -1, "filename": "appsync-gremlin-0.0.16.tar.gz", "has_sig": false, "md5_digest": "8bd27342ac60619a07eb48c95b7a245d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10027, "upload_time": "2019-09-26T10:36:28", "url": "https://files.pythonhosted.org/packages/12/c8/fd13f8096334f6df1f2b481bf7c1017b90aaea3ec960645b85d0f9f11076/appsync-gremlin-0.0.16.tar.gz" } ], "0.0.17": [ { "comment_text": "", "digests": { "md5": "097013ca8ebb5e3ce06df00fee91bfd8", "sha256": "c1b11678949b5ce27ae87114c5f63ee1e76096b6e2022edf6195d207fac41f17" }, "downloads": -1, "filename": "appsync_gremlin-0.0.17-py3-none-any.whl", "has_sig": false, "md5_digest": "097013ca8ebb5e3ce06df00fee91bfd8", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 15888, "upload_time": "2019-09-26T15:04:23", "url": "https://files.pythonhosted.org/packages/0f/5e/11de7079fd5bf7d2d9ad779d50ebcb556caa51935b5c46abf338e0685147/appsync_gremlin-0.0.17-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "dffde19334a4a1ad8843108655ee23a1", "sha256": "10db9d2a58f62ff76b2e5399dcdd269045b8745710440df8c443c01d0a78eefe" }, "downloads": -1, "filename": "appsync-gremlin-0.0.17.tar.gz", "has_sig": false, "md5_digest": "dffde19334a4a1ad8843108655ee23a1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10044, "upload_time": "2019-09-26T15:04:25", "url": "https://files.pythonhosted.org/packages/93/93/ed2786ad010698118f1a00b4839160be0a106a826cea28e07a87978a6f2d/appsync-gremlin-0.0.17.tar.gz" } ], "0.0.18": [ { "comment_text": "", "digests": { "md5": "01f4a2fcbd2bc60953a06d29721e106e", "sha256": "768b570540767f09570d5b5c3962d160092b707668c5774a7575756867416dd3" }, "downloads": -1, "filename": "appsync_gremlin-0.0.18-py3-none-any.whl", "has_sig": false, "md5_digest": "01f4a2fcbd2bc60953a06d29721e106e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 15960, "upload_time": "2019-09-27T16:29:10", "url": "https://files.pythonhosted.org/packages/6a/51/b190d00988d5d7a4b1087905b50e2fef6f76b07d4d2eb41f672cd1617416/appsync_gremlin-0.0.18-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b44fcf17c35400977a38d50abd0558f7", "sha256": "5d91457c156e0fe1219f3cadbded94cf2f819cffd61507d9278bd908d347de19" }, "downloads": -1, "filename": "appsync-gremlin-0.0.18.tar.gz", "has_sig": false, "md5_digest": "b44fcf17c35400977a38d50abd0558f7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10108, "upload_time": "2019-09-27T16:29:12", "url": "https://files.pythonhosted.org/packages/bf/c4/5fef6eceae6bc86c0e5a2a604bbf703908463424e7f4fc3361eb94d95df2/appsync-gremlin-0.0.18.tar.gz" } ], "0.0.19": [ { "comment_text": "", "digests": { "md5": "53743582416cc5cd252b4b5292ec54fe", "sha256": "2401e7ff208b8a4e35480da445b688b40e872bfc4474a60875f36542aa6e44d4" }, "downloads": -1, "filename": "appsync_gremlin-0.0.19-py3-none-any.whl", "has_sig": false, "md5_digest": "53743582416cc5cd252b4b5292ec54fe", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 14204, "upload_time": "2019-10-14T15:55:07", "url": "https://files.pythonhosted.org/packages/27/66/d7b29c12f1f88d93d7b56ebe2d8d19fe59dd55ea782c02c3e3f2dc3c0fa5/appsync_gremlin-0.0.19-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "124cb50a9300979488e2bc42f4b97a40", "sha256": "d548cfe1c114df3bd249a7456d824ff89ec294523b2131d45389202a2a574d17" }, "downloads": -1, "filename": "appsync-gremlin-0.0.19.tar.gz", "has_sig": false, "md5_digest": "124cb50a9300979488e2bc42f4b97a40", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12670, "upload_time": "2019-10-14T15:55:08", "url": "https://files.pythonhosted.org/packages/09/ae/5f0ae88df9da2f57f9b1a4bfa0eb462c7ec9c0794fb9490efdf3e4434a8e/appsync-gremlin-0.0.19.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "e4f36275614dedbb46dd5e595e545d42", "sha256": "4251c70a28609dbfb19e5797ea309dbdb6d334e1e784151f0c5c61cb741f866b" }, "downloads": -1, "filename": "appsync_gremlin-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "e4f36275614dedbb46dd5e595e545d42", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7850, "upload_time": "2019-09-18T13:13:06", "url": "https://files.pythonhosted.org/packages/a9/cc/08d96d9f3c4b109861fd720db33ac0ed5f35098563474cddcee852f7494d/appsync_gremlin-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4a091cc19c07e36f21cb81f9e029fc02", "sha256": "1c8f7753b9ed0fe203c481ca352fe79dd9f7b92f456930926601a293f7aa07a0" }, "downloads": -1, "filename": "appsync-gremlin-0.0.2.tar.gz", "has_sig": false, "md5_digest": "4a091cc19c07e36f21cb81f9e029fc02", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6083, "upload_time": "2019-09-18T13:13:08", "url": "https://files.pythonhosted.org/packages/a5/07/4e9f4f12dea6fd95727fc2ffa8ea26ca69d384d7febca426b4f3cadff769/appsync-gremlin-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "857ba1412490514bdfaa868197b9372d", "sha256": "b05914a33e7b1d93d291b25e757cea1c2c929e95600b72ad324c1dda00398306" }, "downloads": -1, "filename": "appsync_gremlin-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "857ba1412490514bdfaa868197b9372d", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7899, "upload_time": "2019-09-18T19:53:52", "url": "https://files.pythonhosted.org/packages/c2/bb/d0e33f9afa2df1da349c68a191e35caf28d1aa52b38bfb670c42ecf42478/appsync_gremlin-0.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b916c6300aa42494682708f70db03069", "sha256": "bbdbc2c2a232a7993bd35fbfaae3b69a7356a1f0fe659fcb02bbe2bb7ef2bd39" }, "downloads": -1, "filename": "appsync-gremlin-0.0.3.tar.gz", "has_sig": false, "md5_digest": "b916c6300aa42494682708f70db03069", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6128, "upload_time": "2019-09-18T19:53:54", "url": "https://files.pythonhosted.org/packages/69/a0/9c9d8e7663142c12354df2502cc3deeb3765e2746252a8497726850d42e4/appsync-gremlin-0.0.3.tar.gz" } ], "0.0.4": [ { "comment_text": "", "digests": { "md5": "180a9ee5f94f303956d5d77089bdec74", "sha256": "34152c4efb686b24cdc276be4ef408ee50ddab035d6480f79dad46d3905b7793" }, "downloads": -1, "filename": "appsync_gremlin-0.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "180a9ee5f94f303956d5d77089bdec74", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7898, "upload_time": "2019-09-18T20:02:25", "url": "https://files.pythonhosted.org/packages/a3/5c/e43c3789dfdda8ad15ab8cffb13b4bbf584b84c53844513d94409629b9fe/appsync_gremlin-0.0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9478823d72cc2db628d4989da92fd0b4", "sha256": "963231c7cfee38ed65b8dfcdba66493773120fcae5659398d5cf63d0d159a117" }, "downloads": -1, "filename": "appsync-gremlin-0.0.4.tar.gz", "has_sig": false, "md5_digest": "9478823d72cc2db628d4989da92fd0b4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6126, "upload_time": "2019-09-18T20:02:27", "url": "https://files.pythonhosted.org/packages/eb/9d/f054e595092a84630da06cc6169750387c327dfd6eac118197fd6b670202/appsync-gremlin-0.0.4.tar.gz" } ], "0.0.5": [ { "comment_text": "", "digests": { "md5": "dac40a8d2544b33c1dacbada23bdf5a4", "sha256": "8c047f5116ae3c96bceb92d07cba1ce52eed42ad01ac3b51476989b2b5e38873" }, "downloads": -1, "filename": "appsync_gremlin-0.0.5-py3-none-any.whl", "has_sig": false, "md5_digest": "dac40a8d2544b33c1dacbada23bdf5a4", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8064, "upload_time": "2019-09-18T20:18:13", "url": "https://files.pythonhosted.org/packages/02/62/6d55b6d48369a4cee8f2a0dee15f0cc45112f670952626e6885c9c663044/appsync_gremlin-0.0.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3fc97a154509b368095e0659691a2c78", "sha256": "59e9a0cef4525b8bc088a6fc9c68b447e5b80886f5f49476476baeb60372d4f4" }, "downloads": -1, "filename": "appsync-gremlin-0.0.5.tar.gz", "has_sig": false, "md5_digest": "3fc97a154509b368095e0659691a2c78", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6294, "upload_time": "2019-09-18T20:18:15", "url": "https://files.pythonhosted.org/packages/e3/de/bc3a5c570f28563c607e0ce59270b8fa38b11a3ddab59d28a0bba0e3ac13/appsync-gremlin-0.0.5.tar.gz" } ], "0.0.6": [ { "comment_text": "", "digests": { "md5": "0bbfd47d250c8c32704a8ea46e397642", "sha256": "60bd37dae8806794ff0c32373d4670c582eb97625fefe2d2e52ff7f6eb16baed" }, "downloads": -1, "filename": "appsync_gremlin-0.0.6-py3-none-any.whl", "has_sig": false, "md5_digest": "0bbfd47d250c8c32704a8ea46e397642", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8060, "upload_time": "2019-09-18T20:30:35", "url": "https://files.pythonhosted.org/packages/b3/e5/c28f5bacbc368bb1896f3d09db557d210c246c7c4b42e0216a4e79ddd744/appsync_gremlin-0.0.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9859981834d5873e472d5f42fb20672a", "sha256": "5b2103d21ca0b6aab6c1754a0b51d59b3d4867ffa3fa35487a0cb93b4e3a4f4d" }, "downloads": -1, "filename": "appsync-gremlin-0.0.6.tar.gz", "has_sig": false, "md5_digest": "9859981834d5873e472d5f42fb20672a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6288, "upload_time": "2019-09-18T20:30:36", "url": "https://files.pythonhosted.org/packages/19/95/9158abad8513d8816a3c3ed86e1c76d94b7801ac625f9f2d7e2ed52fa8ed/appsync-gremlin-0.0.6.tar.gz" } ], "0.0.7": [ { "comment_text": "", "digests": { "md5": "7889dd937515c0f7321fbeb8682a5133", "sha256": "b8874c5a7332be9239adf26f065b670e612c59dc11d00050a3f7986e9211f0bc" }, "downloads": -1, "filename": "appsync_gremlin-0.0.7-py3-none-any.whl", "has_sig": false, "md5_digest": "7889dd937515c0f7321fbeb8682a5133", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8378, "upload_time": "2019-09-19T08:43:22", "url": "https://files.pythonhosted.org/packages/a8/a2/bb837d613907db04d78e9802079fc67c6603b7d8da5f7c7777f3ea09a27a/appsync_gremlin-0.0.7-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "cd16d66e623b0d846a5dd2f899e4182b", "sha256": "0004198bfaa3112e95d9ca6bdc786cc0a7f9b03c3fcc8cc6216ca82a4098dac4" }, "downloads": -1, "filename": "appsync-gremlin-0.0.7.tar.gz", "has_sig": false, "md5_digest": "cd16d66e623b0d846a5dd2f899e4182b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6573, "upload_time": "2019-09-19T08:43:23", "url": "https://files.pythonhosted.org/packages/34/ce/c9add6165ce31f7494109fe4d3808c8341081a8714744c84016405e80f5c/appsync-gremlin-0.0.7.tar.gz" } ], "0.0.8": [ { "comment_text": "", "digests": { "md5": "4382f52ee1ce55fd0c75583d76977130", "sha256": "a1f27269a1f884be250d7034b1e43812a997c6a6e6d572072dc98817c0f58071" }, "downloads": -1, "filename": "appsync_gremlin-0.0.8-py3-none-any.whl", "has_sig": false, "md5_digest": "4382f52ee1ce55fd0c75583d76977130", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 11083, "upload_time": "2019-09-20T13:03:24", "url": "https://files.pythonhosted.org/packages/4d/63/8b94d9965f2ede1aae7d129b80bf088a07958968593cdba2f00fac966c0c/appsync_gremlin-0.0.8-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "699eac356bd689099c645fc7c4ba5ca2", "sha256": "4b5726e8ab76245d52d644c5ae946e8e07b4d7a93ed5230d4d96842f5a528c23" }, "downloads": -1, "filename": "appsync-gremlin-0.0.8.tar.gz", "has_sig": false, "md5_digest": "699eac356bd689099c645fc7c4ba5ca2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8230, "upload_time": "2019-09-20T13:03:25", "url": "https://files.pythonhosted.org/packages/ae/4a/4af2e8a79a137ea8f66a2278f50901ba508c2eaff0b9e3ed5549748862a0/appsync-gremlin-0.0.8.tar.gz" } ], "0.0.9": [ { "comment_text": "", "digests": { "md5": "4419db95eed6388e8a9f32c5a993444b", "sha256": "847f31834b617576e130a0d08b512cc89e39e0d0c8357e4e5f915b49c0fb129c" }, "downloads": -1, "filename": "appsync_gremlin-0.0.9-py3-none-any.whl", "has_sig": false, "md5_digest": "4419db95eed6388e8a9f32c5a993444b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 11103, "upload_time": "2019-09-20T14:32:55", "url": "https://files.pythonhosted.org/packages/bd/69/67b9401fa68caa2722b93ae0af9847b23938ce7fc1429fcff0a02c638b0f/appsync_gremlin-0.0.9-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "48151595e27f329a3fcdf749aa6e762e", "sha256": "58d7ae9a1fcf782c15a6f630384393d2d4fcfc3a343918dde5eddc2fff0d0e27" }, "downloads": -1, "filename": "appsync-gremlin-0.0.9.tar.gz", "has_sig": false, "md5_digest": "48151595e27f329a3fcdf749aa6e762e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8245, "upload_time": "2019-09-20T14:32:57", "url": "https://files.pythonhosted.org/packages/7e/12/1ab83b5fb0803eb6b2861c48c77eb569d3dde1e65d80f689c4b4aff6e745/appsync-gremlin-0.0.9.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "53743582416cc5cd252b4b5292ec54fe", "sha256": "2401e7ff208b8a4e35480da445b688b40e872bfc4474a60875f36542aa6e44d4" }, "downloads": -1, "filename": "appsync_gremlin-0.0.19-py3-none-any.whl", "has_sig": false, "md5_digest": "53743582416cc5cd252b4b5292ec54fe", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 14204, "upload_time": "2019-10-14T15:55:07", "url": "https://files.pythonhosted.org/packages/27/66/d7b29c12f1f88d93d7b56ebe2d8d19fe59dd55ea782c02c3e3f2dc3c0fa5/appsync_gremlin-0.0.19-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "124cb50a9300979488e2bc42f4b97a40", "sha256": "d548cfe1c114df3bd249a7456d824ff89ec294523b2131d45389202a2a574d17" }, "downloads": -1, "filename": "appsync-gremlin-0.0.19.tar.gz", "has_sig": false, "md5_digest": "124cb50a9300979488e2bc42f4b97a40", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12670, "upload_time": "2019-10-14T15:55:08", "url": "https://files.pythonhosted.org/packages/09/ae/5f0ae88df9da2f57f9b1a4bfa0eb462c7ec9c0794fb9490efdf3e4434a8e/appsync-gremlin-0.0.19.tar.gz" } ] }