diff --git a/neo4j/v1/api.py b/neo4j/v1/api.py index 306c534ab..0ce67a0b4 100644 --- a/neo4j/v1/api.py +++ b/neo4j/v1/api.py @@ -22,7 +22,7 @@ from collections import deque from random import random from threading import RLock -from time import clock, sleep +from time import time, sleep from warnings import warn from neo4j.bolt import ProtocolError, ServiceUnavailable @@ -425,7 +425,7 @@ def _run_transaction(self, access_mode, unit_of_work, *args, **kwargs): RETRY_DELAY_MULTIPLIER, RETRY_DELAY_JITTER_FACTOR) last_error = None - t0 = t1 = clock() + t0 = t1 = time() while t1 - t0 <= self._max_retry_time: try: self._create_transaction() @@ -436,7 +436,7 @@ def _run_transaction(self, access_mode, unit_of_work, *args, **kwargs): except (ServiceUnavailable, SessionExpired) as error: last_error = error sleep(next(retry_delay)) - t1 = clock() + t1 = time() raise last_error def read_transaction(self, unit_of_work, *args, **kwargs): diff --git a/neo4j/v1/session.py b/neo4j/v1/session.py index 855f9860a..b3cbd1111 100644 --- a/neo4j/v1/session.py +++ b/neo4j/v1/session.py @@ -47,8 +47,11 @@ def __run__(self, statement, parameters): result.statement = statement result.parameters = parameters - self._connection.append(RUN, (statement, parameters), response=run_response) - self._connection.append(PULL_ALL, response=pull_all_response) + try: + self._connection.append(RUN, (statement, parameters), response=run_response) + self._connection.append(PULL_ALL, response=pull_all_response) + except AttributeError: + pass return result diff --git a/test/examples/__main__.py b/test/examples/__main__.py new file mode 100644 index 000000000..9487b7a0e --- /dev/null +++ b/test/examples/__main__.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +if __name__ == "__main__": + from os.path import dirname + from test.tools import run_tests + run_tests(dirname(__file__)) diff --git a/test/examples/autocommit_transaction_example.py b/test/examples/autocommit_transaction_example.py new file mode 100644 index 000000000..71525d078 --- /dev/null +++ b/test/examples/autocommit_transaction_example.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::autocommit-transaction-import[] +from neo4j.v1 import Session; +from base_application import BaseApplication +# end::autocommit-transaction-import[] + +class AutocommitTransactionExample(BaseApplication): + def __init__(self, uri, user, password): + super(AutocommitTransactionExample, self).__init__(uri, user, password) + + # tag::autocommit-transaction[] + def add_person(self, name): + session = self._driver.session() + session.run( "CREATE (a:Person {name: $name})", {"name": name} ) + # end::autocommit-transaction[] diff --git a/test/examples/base_application.py b/test/examples/base_application.py new file mode 100644 index 000000000..5d0acab85 --- /dev/null +++ b/test/examples/base_application.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from neo4j.v1 import GraphDatabase + +class BaseApplication(object): + def __init__(self, uri, user, password): + self._driver = GraphDatabase.driver( uri, auth=( user, password ) ) + + def close(self): + self._driver.close(); diff --git a/test/examples/basic_auth_example.py b/test/examples/basic_auth_example.py new file mode 100644 index 000000000..98e08689d --- /dev/null +++ b/test/examples/basic_auth_example.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::basic-auth-import[] +from neo4j.v1 import GraphDatabase +# end::basic-auth-import[] + +class BasicAuthExample: + # tag::basic-auth[] + def __init__(self, uri, user, password): + self._driver = GraphDatabase.driver(uri, auth=(user, password)) + # end::basic-auth[] + + def close(self): + self._driver.close() + + def can_connect(self): + record_list = list(self._driver.session().run("RETURN 1")) + return int(record_list[0][0]) == 1 diff --git a/test/examples/config_connection_timeout_example.py b/test/examples/config_connection_timeout_example.py new file mode 100644 index 000000000..1e6395214 --- /dev/null +++ b/test/examples/config_connection_timeout_example.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::config-connection-timeout-import[] +from neo4j.v1 import GraphDatabase +# end::config-connection-timeout-import[] + +class ConfigConnectionTimeoutExample: + # tag::config-connection-timeout[] + def __init__(self, uri, user, password): + self._driver = GraphDatabase.driver( uri, auth=( user, password ), + Config.build().withConnectionTimeout( 15, SECONDS ).toConfig() ) + # end::config-connection-timeout[] + + def close(self): + self._driver.close(); diff --git a/test/examples/config_max_retry_time_example.py b/test/examples/config_max_retry_time_example.py new file mode 100644 index 000000000..a9b82593c --- /dev/null +++ b/test/examples/config_max_retry_time_example.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::config-max-retry-time-import[] +from neo4j.v1 import GraphDatabase +# end::config-max-retry-time-import[] + +class ConfigMaxRetryTimeExample: + # tag::config-max-retry-time[] + def __init__(self, uri, user, password): + self._driver = GraphDatabase.driver(uri, auth=(user, password), + Config.build().withMaxTransactionRetryTime( 15, SECONDS ).toConfig() ) + # end::config-max-retry-time[] + + def close(self): + self._driver.close(); diff --git a/test/examples/config_trust_example.py b/test/examples/config_trust_example.py new file mode 100644 index 000000000..9fa4ee457 --- /dev/null +++ b/test/examples/config_trust_example.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::config-trust-import[] +from neo4j.v1 import GraphDatabase +# end::config-trust-import[] + +class ConfigTrustExample: + # tag::config-trust[] + def __init__(self, uri, user, password): + self._driver = GraphDatabase.driver(uri, auth=(user, password), + Config.build().withTrustStrategy( Config.TrustStrategy.trustSystemCertificates() ).toConfig() ) + # end::config-trust[] + + def close(self): + self._driver.close(); diff --git a/test/examples/config_unencrypted_example.py b/test/examples/config_unencrypted_example.py new file mode 100644 index 000000000..f888e90de --- /dev/null +++ b/test/examples/config_unencrypted_example.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::config-unencrypted-import[] +from neo4j.v1 import GraphDatabase +# end::config-unencrypted-import[] + +class ConfigUnencryptedExample: + # tag::config-unencrypted[] + def __init__(self, uri, user, password): + self._driver = GraphDatabase.driver(uri, auth=(user, password), encrypted=False) + # end::config-unencrypted[] + + def close(self): + self._driver.close(); diff --git a/test/examples/custom_auth_example.py b/test/examples/custom_auth_example.py new file mode 100644 index 000000000..ac46bb05e --- /dev/null +++ b/test/examples/custom_auth_example.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::custom-auth-import[] +from neo4j.v1 import GraphDatabase; +# end::custom-auth-import[] + +class CustomAuthExample: + # tag::custom-auth[] + def __init__(self, uri, principal, credentials, realm, scheme, parameters): + self._driver = GraphDatabase.driver( uri, auth=(principal, credentials, realm, scheme, parameters)) + # end::custom-auth[] + + def close(self): + self._driver.close() diff --git a/test/examples/cypher_error_example.py b/test/examples/cypher_error_example.py new file mode 100644 index 000000000..ea75c00f0 --- /dev/null +++ b/test/examples/cypher_error_example.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::cypher-error-import[] +from neo4j.v1 import GraphDatabase, ClientError +from base_application import BaseApplication +# end::cypher-error-import[] + +class CypherErrorExample(BaseApplication): + def __init__(self, uri, user, password): + super(CypherErrorExample, self).__init__(uri, user, password) + + # tag::cypher-error[] + def get_employee_number(self, name): + session = self._driver.session() + session.read_transaction(lambda tx: self.select_employee(tx, name)) + + def select_employee(self, tx, name): + try: + record_list = list(tx.run("SELECT * FROM Employees WHERE name = $name", {"name": name})) + return int(record_list[0]["employee_number"]) + except ClientError as e: + print(e.message) + return -1 + # end::cypher-error[] diff --git a/test/examples/driver_lifecycle_example.py b/test/examples/driver_lifecycle_example.py new file mode 100644 index 000000000..cc1506488 --- /dev/null +++ b/test/examples/driver_lifecycle_example.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::driver-lifecycle-import[] +from neo4j.v1 import GraphDatabase +# end::driver-lifecycle-import[] + +# tag::driver-lifecycle[] +class DriverLifecycleExample: + def __init__(self, uri, user, password): + self._driver = GraphDatabase.driver(uri, auth=(user, password)) + + def close(self): + self._driver.close(); +# end::driver-lifecycle[] diff --git a/test/examples/hello_world_example.py b/test/examples/hello_world_example.py new file mode 100644 index 000000000..d9e3df8be --- /dev/null +++ b/test/examples/hello_world_example.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::hello-world-import[] +from neo4j.v1 import GraphDatabase +from base_application import BaseApplication +# end::hello-world-import[] + +# tag::hello-world[] +class HelloWorldExample(BaseApplication): + def __init__(self, uri, user, password): + super(HelloWorldExample, self).__init__(uri, user, password) + + def _create_and_return_greeting(self, tx, message): + record_list = list(tx.run("CREATE (a:Greeting) " + + "SET a.message = $message " + + "RETURN a.message + ', from node ' + id(a)", + {"message": message})) + return str(record_list[0][0]) + + def print_greeting(self, message): + with self._driver.session() as session: + greeting = session.write_transaction(lambda tx: self._create_and_return_greeting(tx, message)) + print(greeting) +# end::hello-world[] + +# tag::hello-world-output[] +# hello, world, from node 1234 +# end::hello-world-output[] diff --git a/test/examples/read_write_transaction_example.py b/test/examples/read_write_transaction_example.py new file mode 100644 index 000000000..ec5bef984 --- /dev/null +++ b/test/examples/read_write_transaction_example.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::read-write-transaction-import[] +from neo4j.v1 import GraphDatabase +from base_application import BaseApplication +# end::read-write-transaction-import[] + +class ReadWriteTransactionExample(BaseApplication): + def __init__(self, uri, user, password): + super(ReadWriteTransactionExample, self).__init__(uri, user, password) + + # tag::read-write-transaction[] + def add_person(self, name): + with self._driver.session() as session: + session.write_transaction(lambda tx: self.create_person_node(tx, name)) + return session.read_transaction(lambda tx: self.match_person_node(tx, name)) + + def create_person_node(self, tx, name): + tx.run("CREATE (a:Person {name: $name})", {"name": name }) + return None + + def match_person_node(self, tx, name): + record_list = list(tx.run("MATCH (a:Person {name: $name}) RETURN count(a)", {"name": name })) + return int(record_list[0][0]) + # end::read-write-transaction[] diff --git a/test/examples/result_consume_example.py b/test/examples/result_consume_example.py new file mode 100644 index 000000000..02ffc2487 --- /dev/null +++ b/test/examples/result_consume_example.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::result-consume-import[] +from neo4j.v1 import GraphDatabase +from base_application import BaseApplication +# end::result-consume-import[] + +class ResultConsumeExample(BaseApplication): + def __init__(self, uri, user, password): + super(ResultConsumeExample, self).__init__(uri, user, password) + + # tag::result-consume[] + def get_people(self): + with self._driver.session() as session: + return session.read_transaction(self.match_person_nodes) + + def match_person_nodes(self, tx): + names = [] + results = tx.run("MATCH (a:Person) RETURN a.name ORDER BY a.name") + + for result in results: + names.append(result["a.name"]) + + return names + # end::result-consume[] diff --git a/test/examples/result_retain_example.py b/test/examples/result_retain_example.py new file mode 100644 index 000000000..ddf375357 --- /dev/null +++ b/test/examples/result_retain_example.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::result-retain-import[] +from neo4j.v1 import GraphDatabase +from base_application import BaseApplication +# end::result-retain-import[] + +class ResultRetainExample(BaseApplication): + def __init__(self, uri, user, password): + super(ResultRetainExample, self).__init__(uri, user, password) + + # tag::result-retain[] + def add_employees(self, company_name): + with self._driver.session() as session: + employees = 0 + persons = session.read_transaction(self.match_person_nodes) + + for person in persons: + num = session.write_transaction(self.add_employee_to_company(person, company_name)) + employees = employees + num + + return employees + + def add_employee_to_company(self, person, company_name): + def do_transaction(tx): + tx.run("MATCH (emp:Person {name: $person_name}) " + + "MERGE (com:Company {name: $company_name}) " + + "MERGE (emp)-[:WORKS_FOR]->(com)", + {"person_name": person["name"], + "company_name": company_name}) + return 1 + return do_transaction + + def match_person_nodes(self, tx): + return list(tx.run("MATCH (a:Person) RETURN a.name AS name")) + # end::result-retain[] diff --git a/test/examples/service_unavailable_example.py b/test/examples/service_unavailable_example.py new file mode 100644 index 000000000..7dba85f08 --- /dev/null +++ b/test/examples/service_unavailable_example.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::service-unavailable-import[] +from neo4j.v1 import GraphDatabase, ServiceUnavailable +from base_application import BaseApplication +# end::service-unavailable-import[] + +class ServiceUnavailableExample(BaseApplication): + def __init__(self, uri, user, password): + super(ServiceUnavailableExample, self).__init__(uri, user, password) + + # tag::service-unavailable[] + def addItem(self): + session = self._driver.session() + try: + session.write_transaction(lambda tx: tx.run("CREATE (a:Item)")) + return True + except ServiceUnavailable as e: + return False + # end::service-unavailable[] diff --git a/test/examples/session_example.py b/test/examples/session_example.py new file mode 100644 index 000000000..612416cd6 --- /dev/null +++ b/test/examples/session_example.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::session-import[] +from base_application import BaseApplication +# end::session-import[] + +class SessionExample(BaseApplication): + def __init__(self, uri, user, password): + super(SessionExample, self).__init__(uri, user, password) + + # tag::session[] + def do_work(self): + session = self._driver.session() + # TODO: something with the Session + # end::session[] diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py new file mode 100644 index 000000000..564ab95b5 --- /dev/null +++ b/test/examples/test_examples.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from test.integration.tools import IntegrationTestCase + + +## Python2 doesn't have contextlib.redirect_stdout() +# http://eli.thegreenplace.net/2015/redirecting-all-kinds-of-stdout-in-python/ +import sys +from contextlib import contextmanager +@contextmanager +def stdout_redirector(stream): + old_stdout = sys.stdout + sys.stdout = stream + try: + yield + finally: + sys.stdout = old_stdout + +def get_string_io(): + if sys.version_info[0] < 3: + from StringIO import StringIO + else: + from io import StringIO + return StringIO() + +class ExamplesTest(IntegrationTestCase): + + def setUp(self): + self.clean() + + def test_autocommit_transaction_example(self): + from autocommit_transaction_example import AutocommitTransactionExample + + example = AutocommitTransactionExample(self.bolt_uri, self.user, self.password) + example.add_person('Alice') + + self.assertTrue(self.person_count('Alice') > 0) + + def test_basic_auth_example(self): + from basic_auth_example import BasicAuthExample + + example = BasicAuthExample(self.bolt_uri, self.user, self.password) + + self.assertTrue(example.can_connect()) + + def test_config_unencrypted_example(self): + from config_unencrypted_example import ConfigUnencryptedExample + + example = ConfigUnencryptedExample(self.bolt_uri, self.user, self.password) + + self.assertIsInstance(example, ConfigUnencryptedExample) + + def test_cypher_error_example(self): + from cypher_error_example import CypherErrorExample + + f = get_string_io() + with stdout_redirector(f): + example = CypherErrorExample(self.bolt_uri, self.user, self.password) + try: + example.get_employee_number('Alice') + except: + pass + + self.assertTrue(f.getvalue().startswith( + """Invalid input 'L': expected 't/T' (line 1, column 3 (offset: 2)) +"SELECT * FROM Employees WHERE name = $name" + ^""")) + + def test_driver_lifecycle_example(self): + from driver_lifecycle_example import DriverLifecycleExample + + example = DriverLifecycleExample(self.bolt_uri, self.user, self.password) + example.close() + + self.assertIsInstance(example, DriverLifecycleExample) + + def test_hello_world_example(self): + from hello_world_example import HelloWorldExample + + f = get_string_io() + with stdout_redirector(f): + example = HelloWorldExample(self.bolt_uri, self.user, self.password) + example.print_greeting("hello, world") + example.close() + + self.assertTrue(f.getvalue().startswith("hello, world, from node")) + + def test_read_write_transaction_example(self): + from read_write_transaction_example import ReadWriteTransactionExample + + example = ReadWriteTransactionExample(self.bolt_uri, self.user, self.password) + node_count = example.add_person('Alice') + + self.assertTrue(node_count > 0) + + def test_result_consume_example(self): + from result_consume_example import ResultConsumeExample + + self.write("CREATE (a:Person {name: 'Alice'})") + self.write("CREATE (a:Person {name: 'Bob'})") + example = ResultConsumeExample(self.bolt_uri, self.user, self.password) + people = list(example.get_people()) + + self.assertEqual(['Alice', 'Bob'], people) + + def test_result_retain_example(self): + from result_retain_example import ResultRetainExample + + self.write("CREATE (a:Person {name: 'Alice'})") + self.write("CREATE (a:Person {name: 'Bob'})") + example = ResultRetainExample(self.bolt_uri, self.user, self.password) + example.add_employees('Acme') + employee_count = self.read("MATCH (emp:Person)-[:WORKS_FOR]->(com:Company) WHERE com.name = 'Acme' RETURN count(emp)").single()[0] + + self.assertEqual(employee_count, 2) + + def test_session_example(self): + from session_example import SessionExample + + example = SessionExample(self.bolt_uri, self.user, self.password) + example.do_work() + + self.assertIsInstance(example, SessionExample) + + def test_transaction_function_example(self): + from transaction_function_example import TransactionFunctionExample + + example = TransactionFunctionExample(self.bolt_uri, self.user, self.password) + example.add_person("Alice") + + self.assertEqual(self.person_count("Alice"), 1) + + + def read(self, statement): + from neo4j.v1 import GraphDatabase + with GraphDatabase.driver(self.bolt_uri, auth=self.auth_token) as driver: + with driver.session() as session: + return session.read_transaction(lambda tx: tx.run(statement)) + + def write(self, statement): + from neo4j.v1 import GraphDatabase + with GraphDatabase.driver(self.bolt_uri, auth=self.auth_token) as driver: + with driver.session() as session: + return session.write_transaction(lambda tx: tx.run(statement)) + + def clean(self): + self.write("MATCH (a) DETACH DELETE a") + + def person_count(self, name): + from neo4j.v1 import GraphDatabase + with GraphDatabase.driver(self.bolt_uri, auth=self.auth_token) as driver: + with driver.session() as session: + record_list = list(session.run("MATCH (a:Person {name: $name}) RETURN count(a)", {"name": name})) + return len(record_list) + + +class ServiceUnavailableTest(IntegrationTestCase): + + def test_service_unavailable_example(self): + from service_unavailable_example import ServiceUnavailableExample + + example = ServiceUnavailableExample(self.bolt_uri, self.user, self.password) + self.__class__._stop_server() + + self.assertFalse(example.addItem()) diff --git a/test/examples/transaction_function_example.py b/test/examples/transaction_function_example.py new file mode 100644 index 000000000..29893a2db --- /dev/null +++ b/test/examples/transaction_function_example.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +# Copyright (c) 2002-2017 "Neo Technology," +# Network Engine for Objects in Lund AB [http://neotechnology.com] +# +# This file is part of Neo4j. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# tag::transaction-function-import[] +from neo4j.v1 import GraphDatabase +from base_application import BaseApplication +# end::transaction-function-import[] + +class TransactionFunctionExample(BaseApplication): + def __init__(self, uri, user, password): + super(TransactionFunctionExample, self).__init__(uri, user, password) + + # tag::transaction-function[] + def add_person(self, name): + with self._driver.session() as session: + session.write_transaction(lambda tx: self.create_person_node(tx, name)) + + def create_person_node(self, tx, name): + tx.run("CREATE (a:Person {name: $name})", {"name": name}) + return 1 + # end::transaction-function[] +