Repository: ziyasal/pyley
Branch: master
Commit: a2b961abfd5f
Files: 18
Total size: 26.5 KB
Directory structure:
gitextract_tu09thrq/
├── .appveyor.sh
├── .gitignore
├── .travis.sh
├── .travis.yml
├── MANIFEST.in
├── README.rst
├── UNLICENSE
├── appveyor.yml
├── pyley/
│ ├── __init__.py
│ └── pyley.py
├── requirements.testing.txt
├── requirements.txt
├── setup.cfg
├── setup.py
├── tests/
│ ├── __init__.py
│ ├── test_cayley_client.py
│ └── test_gizmo_query.py
└── tox.ini
================================================
FILE CONTENTS
================================================
================================================
FILE: .appveyor.sh
================================================
appveyor DownloadFile https://github.com/cayleygraph/cayley/releases/download/v0.7.0/cayley_0.7.0_windows_amd64.zip -Timeout 5000
7z x cayley_0.7.0_windows_amd64.zip cayley_0.7.0_windows_amd64
cd /?
cd cayley_0.7.0_windows_amd64
cd /?
dir /a
cayley.exe http --dbpath=30kmoviedata.nq.gz &
sleep 2
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
#PyCharm project folder
.idea/
# Distribution / packaging
.Python
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Rope
.ropeproject
# Django stuff:
*.log
*.pot
# Sphinx documentation
docs/_build/
================================================
FILE: .travis.sh
================================================
#!/bin/bash
wget https://github.com/cayleygraph/cayley/releases/download/v0.7.0/cayley_0.7.0_linux_amd64.tar.gz
tar -xvzf cayley_0.7.0_linux_amd64.tar.gz
cd cayley_0.7.0_linux_amd64
./cayley http --dbpath=30kmoviedata.nq.gz &
sleep 2
================================================
FILE: .travis.yml
================================================
language: python
python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"
- "3.7"
- "3.8"
before_script:
- /bin/bash ./.travis.sh
install:
- pip install -r requirements.txt
- pip install -r requirements.testing.txt
- pip install .
script:
- nosetests --with-coverage --cover-package=pyley
after_success:
- coveralls
================================================
FILE: MANIFEST.in
================================================
include README.md
================================================
FILE: README.rst
================================================
.. image:: https://github.com/ziyasal/pyley/raw/master/pyley.png?raw=true
pyley
=====
.. image:: https://img.shields.io/pypi/v/pyley.svg
:target: https://pypi.org/project/pyley
.. image:: https://img.shields.io/pypi/pyversions/pyley.svg
:target: https://pypi.org/project/pyley
.. image:: https://travis-ci.org/ziyasal/pyley.svg?branch=master
:target: https://travis-ci.org/ziyasal/pyley
.. image:: https://coveralls.io/repos/ziyasal/pyley/badge.svg?branch=master&service=github
:target: https://coveralls.io/github/ziyasal/pyley?branch=master
`Python `_ client for an open-source graph database **Cayley** ``_.
Cayley is an open-source graph inspired by the graph database behind `Freebase `_ and Google's `Knowledge Graph `_. Its goal is to be a part of the developer's toolbox where `Linked Data `_ and graph-shaped data (semantic webs, social networks, etc) in general are concerned.
Install via pip
---------------
You can install pyley using::
$ pip install pyley
Sample
------
**Import pyley:**
.. code-block:: python
from pyley import CayleyClient, GraphObject
# Create cayley client
# this creates client with default parameters `http://localhost:64210/api/v1/query/gizmo`
client = CayleyClient()
# or specify `url` and `version` parameters
client = CayleyClient("http://localhost:64210", "v1")
g = GraphObject()
# Query all vertices in the graph, limit to the first 5 vertices found.
g.Vertex().GetLimit(5)
# Start with only one vertex, the literal name "Humphrey Bogart", and retrieve all of them.
query = g.Vertex("Humphrey Bogart").All();
response = client.Send(query)
# response.result contains JSON data and response.r contains raw response
print response.result
# `g` and `V` are synonyms for `graph` and `Vertex` respectively, as they are quite common.
query = g.V("Humphrey Bogart").All()
response = client.Send(query)
# "Humphrey Bogart" is a name, but not an entity.
# Let's find the entities with this name in our dataset.
# Follow links that are pointing In to our "Humphrey Bogart" node with the predicate "name".
query = g.V("Humphrey Bogart").In("").All()
response = client.Send(query)
# Notice that "name" is a generic predicate in our dataset.
# Starting with a movie gives a similar effect.
query = g.V("Casablanca").In("name").All()
response = client.Send(query)
# Relatedly, we can ask the reverse; all ids with the name "Casablanca"
query = g.V().Has("name", "Casablanca").All()
response = client.Send(query)
# Let's get the list of actors in the film
query = g.V().Has("name", "Casablanca") \
.Out("/film/film/starring") \
.Out("/film/performance/actor") \
.Out("name") \
.All()
response = client.Send(query)
# But this is starting to get long.
# Let's use a morphism -- a pre-defined path stored in a variable -- as our linkage
film_to_actor = g.Morphism().Out("/film/film/starring").Out("/film/performance/actor")
query = g.V() \
.Has("name", "Casablanca") \
.Follow(film_to_actor) \
.Out("name") \
.All()
response = client.Send(query)
# Add data programatically to the JSON result list. Can be any JSON type.
query = g.Emit({'name': "John Doe", 'age': 41, 'isActor': True})
response = client.Send(query)
Bugs
----
If you encounter a bug, performance issue, or malfunction, please add an `Issues `_ with steps on how to reproduce the problem
or feel to free to open a pull request.
TODO
----
- Improve Gizmo implementation (Basic steps implemented at the moment)
- Add more tests
- Add more documentation
Open Source Projects in Use
----------------------------
- `requests `_ by @kennethreitz
License
-------
@ziλasal & @abdullahselek
================================================
FILE: UNLICENSE
================================================
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to
================================================
FILE: appveyor.yml
================================================
environment:
matrix:
- PYTHON: "C:\\Python27"
- PYTHON: "C:\\Python34"
- PYTHON: "C:\\Python35"
- PYTHON: "C:\\Python27-x64"
DISTUTILS_USE_SDK: "1"
- PYTHON: "C:\\Python34-x64"
DISTUTILS_USE_SDK: "1"
- PYTHON: "C:\\Python35-x64"
- PYTHON: "C:\\Python36-x64"
DIR_CAYLEY: C:\cayley
cache:
- '%DIR_CAYLEY% -> appveyor.yml'
install:
- set PATH=%PYTHON%;%PYTHON%\Scripts;C:\OpenSSL-Win64;%DIR_CAYLEY%;%SystemRoot%\system32;%PATH%
- if not exist %DIR_CAYLEY% (
appveyor DownloadFile https://github.com/cayleygraph/cayley/releases/download/v0.7.0/cayley_0.7.0_windows_amd64.zip &&
7z x cayley_0.7.0_windows_amd64.zip -y -aoa -oC:\ > NULs
)
# - appveyor DownloadFile https://github.com/cayleygraph/cayley/releases/download/v0.7.0/cayley_0.7.0_windows_amd64.zip -Timeout 5000
# - 7z x cayley_0.7.0_windows_amd64.zip cayley_0.7.0_windows_amd64
# - cd cayley_0.7.0_windows_amd64
- ps: $CayleyProcess = Start-Process "cayley http --dbpath=30kmoviedata.nq.gz" -PassThru
# We need wheel installed to build wheels
- "%PYTHON%\\python.exe -m pip install wheel"
- "%PYTHON%\\python.exe -m pip install -r requirements.txt"
- "%PYTHON%\\python.exe -m pip install -r requirements.testing.txt"
build: off
test_script:
- "%PYTHON%\\python.exe -m nose --with-coverage --cover-package=pyley"
after_test:
# This step builds your wheels.
- "%PYTHON%\\python.exe setup.py bdist_wheel"
artifacts:
# bdist_wheel puts your built wheel in the dist directory
- path: dist\*
on_finish:
- ps: Stop-Process -Id $CayleyProcess.Id
================================================
FILE: pyley/__init__.py
================================================
"""pyley Python client for an open-source graph database Cayley"""
__title__ = 'pyley'
__version__ = '0.2.2.2'
__author__ = 'Ziya SARIKAYA @ziyasal'
__email__ = 'sarikayaziya@gmail.com',
__license__ = 'MIT License'
__copyright__ = 'Copyright 2014 Ziya SARIKAYA @ziyasal'
__url__ = 'https://github.com/ziyasal/pyley'
__download_url__ = 'https://pypi.org/pypi/pyley'
__description__ = 'Python client for an open-source graph database Cayley'
from .pyley import (
CayleyResponse,
CayleyClient,
GraphObject
)
================================================
FILE: pyley/pyley.py
================================================
import json
import requests
class CayleyResponse(object):
def __init__(self, raw_response, result):
self.r = raw_response
self.result = result
class CayleyClient(object):
def __init__(self, url="http://localhost:64210", version="v1"):
self.url = "%s/api/%s/query/gizmo" % (url, version)
self.write_url = "%s/api/%s/write" % (url, version)
self.delete_url = "%s/api/%s/delete" % (url, version)
def add_query_limit(self, limit):
if isinstance(limit, int):
self.url = self.url + '?limit=' + str(limit)
else:
raise Exception("Invalid parameter for adding query limit, should be integer.")
def Send(self, query):
if isinstance(query, str):
r = requests.post(self.url, data=query.encode('utf-8'))
return CayleyResponse(r, r.json())
elif isinstance(query, _GizmoQuery):
r = requests.post(self.url, data=str(query).encode('utf-8'))
return CayleyResponse(r, r.json())
else:
raise Exception("Invalid query parameter in Send")
def AddQuad(self, subject, predicate, object_, label=None):
return self.AddQuads([(subject, predicate, object_, label)])
def AddQuads(self, quads):
quads = [
{
"subject": q[0],
"predicate": q[1],
"object": q[2],
"label": None if len(q) < 4 else q[3]
}
for q in quads
]
r = requests.post(self.write_url, json=quads)
return CayleyResponse(r, r.json())
def DeleteQuad(self, subject, predicate, object_, label=None):
return self.DeleteQuads([(subject, predicate, object_, label)])
def DeleteQuads(self, quads):
quads = [
{
"subject": q[0],
"predicate": q[1],
"object": q[2],
"label": None if len(q) < 4 else q[3]
}
for q in quads
]
r = requests.post(self.delete_url, json=quads)
return CayleyResponse(r, r.json())
class _GizmoQuery(object):
queryDeclarations = None
def __init__(self):
self.queryDeclarations = []
def __str__(self):
return ".".join([str(d) for d in self.queryDeclarations])
def _put(self, token, *parameters):
q = _QueryDefinition(token, *parameters)
self.queryDeclarations.append(q)
class GraphObject(object):
def V(self):
return _Vertex("g.V()")
def V(self, *node_ids):
builder = []
l = len(node_ids)
for index, node_id in enumerate(node_ids):
if index == l - 1:
builder.append(u"'{0:s}'".format(node_id))
else:
builder.append(u"'{0:s}',".format(node_id))
return _Vertex(u"g.V({0:s})".format("".join(builder)))
def M(self):
return _Morphism("g.Morphism()")
def Vertex(self):
return self.V()
def Vertex(self, *node_ids):
if len(node_ids) == 0:
return self.V()
return self.V(*node_ids)
def Morphism(self):
return self.M()
def Emit(self, data):
return "g.Emit({0:s})".format(json.dumps(data, default=lambda o: o.__dict__, sort_keys=True))
class _Path(_GizmoQuery):
def __init__(self, parent):
_GizmoQuery.__init__(self)
self._put(parent)
def Out(self, predicate=None, tags=None):
self._bounds("Out", predicate, tags)
return self
def In(self, predicate=None, tags=None):
self._bounds("In", predicate, tags)
return self
def Both(self, predicate=None, tags=None):
self._bounds("Both", predicate, tags)
return self
def _bounds(self, method, predicate=None, tags=None):
if predicate is None and tags is None:
self._put("%s()", method)
elif tags is None:
self._put("%s(%s)", method, self._format_input_bounds(predicate))
else:
self._put(
"%s(%s, %s)",
method,
self._format_input_bounds(predicate),
self._format_input_bounds(tags)
)
return self
def _format_input_bounds(self, value):
if type(value) is dict:
return json.dumps(value)
if type(value) is str:
return "'%s'" % value
if value is None:
return 'null'
return value
def Is(self, *nodes):
self._put("Is('%s')", "', '".join(nodes))
return self
def Has(self, predicate, object):
self._put("Has('%s', '%s')", predicate, object)
return self
def HasR(self, predicate, object):
self._put("Has('%s', '%s')", object, predicate)
return self
def Tag(self, *tags):
self._put("Tag(%s)", json.dumps(tags))
return self
def Back(self, tag):
self._put("Back('%s')", tag)
return self
def Save(self, predicate, tag):
self._put("Save('%s', '%s')", predicate, tag)
return self
def Intersect(self, query):
if not isinstance(query, _Vertex) and type(query) is not str:
raise Exception("Invalid parameter in intersect query")
self._put("Intersect(%s)", query)
return self
def Union(self, query):
if not isinstance(query, _Vertex) and type(query) is not str:
raise Exception("Invalid parameter in union query")
self._put("Union(%s)", query)
return self
def Follow(self, query):
if not isinstance(query, _Morphism) and type(query) is not str:
raise Exception("Invalid parameter in follow query")
self._put("Follow(%s)", query)
return self
def FollowR(self, query):
if not isinstance(query, _Morphism) and type(query) is not str:
raise Exception("Invalid parameter in followr query")
self._put("FollowR(%s)", query)
return self
def build(self):
return str(self)
class _Vertex(_Path):
def All(self):
self._put("All()")
return self
def GetLimit(self, limit):
self._put("GetLimit(%d)", limit)
return self
class _Morphism(_Path):
pass
class _QueryDefinition(object):
def __init__(self, token, *parameters):
self.token = token
self.parameters = parameters
def __str__(self):
if len(self.parameters) > 0:
return str(self.token) % self.parameters
else:
return str(self.token)
================================================
FILE: requirements.testing.txt
================================================
python-coveralls
coverage
nose
================================================
FILE: requirements.txt
================================================
requests
================================================
FILE: setup.cfg
================================================
[bdist_wheel]
universal = 1
[aliases]
test = nosetest
[check-manifest]
ignore =
.travis.yml
================================================
FILE: setup.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function
import os
import re
import codecs
from setuptools import setup, find_packages
cwd = os.path.abspath(os.path.dirname(__file__))
def read(filename):
with codecs.open(os.path.join(cwd, filename), 'rb', 'utf-8') as h:
return h.read()
metadata = read(os.path.join(cwd, 'pyley', '__init__.py'))
def extract_metaitem(meta):
meta_match = re.search(r"""^__{meta}__\s+=\s+['\"]([^'\"]*)['\"]""".format(meta=meta),
metadata, re.MULTILINE)
if meta_match:
return meta_match.group(1)
raise RuntimeError('Unable to find __{meta}__ string.'.format(meta=meta))
setup(
name='pyley',
version=extract_metaitem('version'),
license=extract_metaitem('license'),
description=extract_metaitem('description'),
long_description=(read('README.rst')),
author=extract_metaitem('author'),
author_email=extract_metaitem('email'),
url=extract_metaitem('url'),
download_url=extract_metaitem('download_url'),
packages=find_packages(exclude=('tests')),
platforms=['Any'],
install_requires=['requests'],
tests_require=['python-coveralls', 'coverage', 'nose'],
keywords='graph database, cayley, cayley python client, client',
include_package_data=True,
classifiers=[
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Topic :: Software Development :: Libraries :: Python Modules',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
],
)
================================================
FILE: tests/__init__.py
================================================
================================================
FILE: tests/test_cayley_client.py
================================================
from unittest import TestCase
from pyley import CayleyClient, GraphObject
_CLIENT_URL = 'http://localhost:64210'
class CayleyClientTests(TestCase):
def test_add_limit(self):
client = CayleyClient(_CLIENT_URL)
client.add_query_limit(10000)
self.assertEqual(client.url, 'http://localhost:64210/api/v1/query/gizmo?limit=10000')
def test_add_limit_fails(self):
client = CayleyClient(_CLIENT_URL)
with self.assertRaises(Exception):
client.add_query_limit('str')
def test_send(self):
client = CayleyClient(_CLIENT_URL)
g = GraphObject()
query = g.V().Has("name", "Casablanca") \
.Out("/film/film/starring") \
.Out("/film/performance/actor") \
.Out("name") \
.All()
response = client.Send(query)
self.assertTrue(response.r.status_code == 200)
self.assertTrue(response.r is not None)
self.assertTrue(len(response.result) > 0)
query = g.V().HasR("name", "Casablanca") \
.Out("/film/film/starring") \
.Out("/film/performance/actor") \
.Out("name") \
.All()
response = client.Send(query)
self.assertTrue(response.r.status_code == 200)
self.assertTrue(response.r is not None)
self.assertTrue(len(response.result) > 0)
def test_a_add_quad(self):
client = CayleyClient(_CLIENT_URL)
response = client.AddQuad('foo', 'to', 'bar')
self.assertEqual(response.r.status_code, 200)
g = GraphObject()
query = g.V("foo").Out('to').Is('bar').All()
response = client.Send(query)
self.assertEqual(len(response.result['result']), 1)
def test_b_delete_quad(self):
client = CayleyClient(_CLIENT_URL)
response = client.DeleteQuad('foo', 'to', 'bar')
self.assertEqual(response.r.status_code, 200)
g = GraphObject()
query = g.V("foo").Out('to').Is("bar").All()
response = client.Send(query)
self.assertIsNone(response.result['result'])
def test_c_add_quads(self):
client = CayleyClient(_CLIENT_URL)
response = client.AddQuads([
('foo', 'to', 'bar'),
('baz', 'from', 'quux')
])
self.assertEqual(response.r.status_code, 200)
g = GraphObject()
query = g.V("foo").Out('to').Is("bar").Union(
g.V("baz").Out('from').Is("quux")
).All()
response = client.Send(query)
self.assertEqual(len(response.result['result']), 2)
def test_d_delete_quads(self):
client = CayleyClient(_CLIENT_URL)
response = client.DeleteQuads([
('foo', 'to', 'bar'),
('baz', 'from', 'quux')
])
self.assertEqual(response.r.status_code, 200)
g = GraphObject()
query = g.V("foo").Out('to').Is("bar").Union(
g.V("baz").Out('from').Is('quux')
).All()
response = client.Send(query)
self.assertIsNone(response.result['result'])
================================================
FILE: tests/test_gizmo_query.py
================================================
import unittest
from pyley import GraphObject
class GizmoQueryTests(unittest.TestCase):
def setUp(self):
self.opts = dict(url='http://localhost:64210/api/v1/query/gizmo')
def test_vertex_query(self):
g = GraphObject()
query = g.Vertex()
self.assertEqual(query.build(), "g.V()")
def test_vertex_query_with_parameters(self):
g = GraphObject()
query = g.V("Humphrey Bogart")
actual = query.build()
self.assertEqual(actual, "g.V('Humphrey Bogart')")
def test_morphism_query(self):
g = GraphObject()
query = g.Morphism()
self.assertEqual(query.build(), "g.Morphism()")
def test_out_query(self):
g = GraphObject()
query = g.V().Out('name')
actual = query.build()
self.assertEqual(actual, "g.V().Out('name')")
def test_out_query_with_predicate(self):
g = GraphObject()
query = g.V().Out(g.Vertex())
actual = query.build()
self.assertEqual(actual, "g.V().Out(g.V())")
def test_out_query_with_predicate_as_dict_and_label(self):
g = GraphObject()
query = g.V().Out(['foo', 'bar'], 'qux')
actual = query.build()
self.assertEqual(actual, "g.V().Out(['foo', 'bar'], 'qux')")
def test_out_query_with_predicate_as_none_and_label_as_dict(self):
g = GraphObject()
query = g.V().Out(None, ['foo', 'bar'])
actual = query.build()
self.assertEqual(actual, "g.V().Out(null, ['foo', 'bar'])")
def test_in_query(self):
g = GraphObject()
query = g.V().In("name").All()
actual = query.build()
self.assertEqual(actual, "g.V().In('name').All()")
def test_both(self):
g = GraphObject()
query = g.V("F").Both("follows")
actual = query.build()
print(actual)
self.assertEqual(actual, "g.V('F').Both('follows')")
def test_is(self):
g = GraphObject()
query = g.V().Is('B', 'C')
actual = query.build()
self.assertEqual(actual, "g.V().Is('B', 'C')")
def test_tag(self):
g = GraphObject()
query = g.V().Tag('B', 'C')
actual = query.build()
self.assertEqual(actual, 'g.V().Tag(["B", "C"])')
def test_save(self):
g = GraphObject()
query = g.V().Save('B', 'C')
actual = query.build()
self.assertEqual(actual, "g.V().Save('B', 'C')")
def test_back(self):
g = GraphObject()
query = g.V().Back('B')
actual = query.build()
self.assertEqual(actual, "g.V().Back('B')")
def test_all_query(self):
g = GraphObject()
query = g.V("Humphrey Bogart").All()
actual = query.build()
self.assertEqual(actual, "g.V('Humphrey Bogart').All()")
def test_has_query(self):
g = GraphObject()
query = g.V().Has("name", "Casablanca").All()
actual = query.build()
self.assertEqual(actual, "g.V().Has('name', 'Casablanca').All()")
def test_complex_query1(self):
g = GraphObject()
query = g.V().Has("name", "Casablanca") \
.Out("/film/film/starring") \
.Out("/film/performance/actor") \
.Out("name") \
.All()
actual = query.build()
self.assertEqual(actual, "g.V().Has('name', 'Casablanca')"
".Out('/film/film/starring')"
".Out('/film/performance/actor')"
".Out('name')"
".All()")
def test_follow_with_morphism_path_and_typed_query(self):
g = GraphObject()
film_to_actor = g.Morphism().Out("/film/film/starring").Out("/film/performance/actor")
query = g.V().Has("name", "Casablanca").Follow(film_to_actor).Out("name").All()
actual = query.build()
self.assertEqual(actual, "g.V().Has('name', 'Casablanca')"
".Follow("
"g.Morphism().Out('/film/film/starring').Out('/film/performance/actor')"
").Out('name')"
".All()")
def test_follow_with_morphism_path_and_str_query(self):
g = GraphObject()
film_to_actor = g.Morphism().Out("/film/film/starring").Out("/film/performance/actor")
query = g.V().Has("name", "Casablanca").Follow(film_to_actor.build()).Out("name").All()
actual = query.build()
self.assertEqual(actual, "g.V().Has('name', 'Casablanca')"
".Follow("
"g.Morphism().Out('/film/film/starring').Out('/film/performance/actor')"
").Out('name')"
".All()")
def test_follow_with_vertex(self):
g = GraphObject()
with self.assertRaises(Exception):
g.V().Follow(g.V()).build()
def test_union(self):
g = GraphObject()
query = g.Vertex().Union(g.Vertex())
actual = query.build()
self.assertEqual(actual, "g.V().Union(g.V())")
def test_intersect(self):
g = GraphObject()
query = g.Vertex().Intersect(g.Vertex())
actual = query.build()
self.assertEqual(actual, "g.V().Intersect(g.V())")
def test_get_limit(self):
g = GraphObject()
query = g.Vertex().GetLimit(5)
actual = query.build()
self.assertEqual(actual, "g.V().GetLimit(5)")
def test_emit(self):
g = GraphObject()
query = g.Emit({'name': 'John', 'lastName': 'DOE', 'age': 25})
self.assertEqual(query, 'g.Emit({"age": 25, "lastName": "DOE", "name": "John"})')
if __name__ == '__main__':
unittest.main()
================================================
FILE: tox.ini
================================================
[tox]
envlist = clean,py27,py3,py36,pypy,pypy3
skip_missing_interpreters = True
[testenv]
deps = -Ur{toxinidir}/requirements.testing.txt
commands = python -m nose
whitelist_externals = pyenv install -s 2.7.11
pyenv install -s 3.6.1
pyenv install -s pypy-5.3.1
pyenv local 2.7.11 3.6.1 pypy-5.3.1
[testenv:clean]
deps = coverage
commands = coverage erase
[testenv:report]
commands = nosetests --with-coverage --cover-package=pyley