From a011720c4622c91ffc81cd4a1ad7635541a36314 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Fri, 7 Apr 2017 10:39:00 +0200 Subject: [PATCH 01/10] Update the examples for the documentation. --- test/examples/__main__.py | 25 +++ .../autocommit_transaction_example.py | 34 ++++ test/examples/base_application.py | 28 +++ test/examples/basic_auth_example.py | 36 ++++ .../config_connection_timeout_example.py | 33 ++++ .../examples/config_max_retry_time_example.py | 33 ++++ test/examples/config_trust_example.py | 33 ++++ test/examples/config_unencrypted_example.py | 32 ++++ test/examples/custom_auth_example.py | 32 ++++ test/examples/cypher_error_example.py | 45 +++++ test/examples/driver_lifecycle_example.py | 32 ++++ test/examples/hello_world_example.py | 48 +++++ .../read_write_transaction_example.py | 43 +++++ test/examples/result_consume_example.py | 43 +++++ test/examples/result_retain_example.py | 54 ++++++ test/examples/service_unavailable_example.py | 51 ++++++ test/examples/session_example.py | 33 ++++ test/examples/test_examples.py | 166 ++++++++++++++++++ test/examples/transaction_function_example.py | 39 ++++ 19 files changed, 840 insertions(+) create mode 100644 test/examples/__main__.py create mode 100644 test/examples/autocommit_transaction_example.py create mode 100644 test/examples/base_application.py create mode 100644 test/examples/basic_auth_example.py create mode 100644 test/examples/config_connection_timeout_example.py create mode 100644 test/examples/config_max_retry_time_example.py create mode 100644 test/examples/config_trust_example.py create mode 100644 test/examples/config_unencrypted_example.py create mode 100644 test/examples/custom_auth_example.py create mode 100644 test/examples/cypher_error_example.py create mode 100644 test/examples/driver_lifecycle_example.py create mode 100644 test/examples/hello_world_example.py create mode 100644 test/examples/read_write_transaction_example.py create mode 100644 test/examples/result_consume_example.py create mode 100644 test/examples/result_retain_example.py create mode 100644 test/examples/service_unavailable_example.py create mode 100644 test/examples/session_example.py create mode 100644 test/examples/test_examples.py create mode 100644 test/examples/transaction_function_example.py 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..dcfb896a7 --- /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().__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..8c2dc0cd5 --- /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: + 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..45f5a4f25 --- /dev/null +++ b/test/examples/cypher_error_example.py @@ -0,0 +1,45 @@ +#!/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().__init__(uri, user, password) + + # FIXME: this doesn't work because read_transaction behaves + # differently than in Java, so this throws a ClientError + + # tag::cypher-error[] + def get_employee_number(self, name): + with self._driver.session() as session: + return 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..cf86b2344 --- /dev/null +++ b/test/examples/hello_world_example.py @@ -0,0 +1,48 @@ +#!/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 +# end::hello-world-import[] + +# tag::hello-world[] +class HelloWorldExample: + def __init__(self, uri, user, password): + self._driver = GraphDatabase.driver(uri, auth=(user, password)) + + def close(self): + self._driver.close() + + 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..d7d7a4784 --- /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().__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..ba76abe67 --- /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().__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..a8ffab5a7 --- /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().__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..83bbf6499 --- /dev/null +++ b/test/examples/service_unavailable_example.py @@ -0,0 +1,51 @@ +#!/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 +# end::service-unavailable-import[] + +class ServiceUnavailableExample: + def __init__(self, uri, user, password): + self._driver = GraphDatabase.driver( uri, auth=(user, password), Config.build().withMaxTransactionRetryTime( 3, SECONDS ).withLogging( DEV_NULL_LOGGING ).toConfig() ) + + def close(self): + self._driver.close(); + + # tag::service-unavailable[] + def addItem(self): + try ( Session session = driver.session() ) + { + return session.writeTransaction( new TransactionWork() + { + @Override + public Boolean execute( Transaction tx ) + { + tx.run( "CREATE (a:Item)" ); + return true; + } + } ); + } + catch ( ServiceUnavailableException ex ) + { + 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..78acef22d --- /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().__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..704ededb1 --- /dev/null +++ b/test/examples/test_examples.py @@ -0,0 +1,166 @@ +#!/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 + +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_connection_timeout_example(self): + # from config_connection_timeout_example import ConfigConnectionTimeoutExample + # pass + + # def test_config_max_retry_time_example(self): + # from config_max_retry_time_example import ConfigMaxRetryTimeExample + # pass + + # def test_config_trust_example(self): + # from config_trust_example import ConfigTrustExample + # pass + + 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_custom_auth_example(self): + # from custom_auth_example import CustomAuthExample + # pass + + def Xtest_cypher_error_example(self): + from cypher_error_example import CypherErrorExample + + example = CypherErrorExample(self.bolt_uri, self.user, self.password) + employee_number = example.get_employee_number('Alice') + + # FIXME: also check the error output like in the Java example + self.assertEqual(employee_number, -1) + + 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): + import io + from contextlib import redirect_stdout + from hello_world_example import HelloWorldExample + + f = io.StringIO() + with redirect_stdout(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_service_unavailable_example(self): + # from service_unavailable_example import ServiceUnavailableExample + # pass + + 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) diff --git a/test/examples/transaction_function_example.py b/test/examples/transaction_function_example.py new file mode 100644 index 000000000..f50f105e7 --- /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().__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[] + From 7a013d50d5c6469727ebde82a5fbe87fd53e64e5 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Fri, 21 Apr 2017 10:30:45 +0200 Subject: [PATCH 02/10] This behaviour is only in the Java driver. --- test/examples/test_examples.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index 704ededb1..52a42cdac 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -40,18 +40,6 @@ def test_basic_auth_example(self): self.assertTrue(example.can_connect()) - # def test_config_connection_timeout_example(self): - # from config_connection_timeout_example import ConfigConnectionTimeoutExample - # pass - - # def test_config_max_retry_time_example(self): - # from config_max_retry_time_example import ConfigMaxRetryTimeExample - # pass - - # def test_config_trust_example(self): - # from config_trust_example import ConfigTrustExample - # pass - def test_config_unencrypted_example(self): from config_unencrypted_example import ConfigUnencryptedExample @@ -59,10 +47,6 @@ def test_config_unencrypted_example(self): self.assertIsInstance(example, ConfigUnencryptedExample) - # def test_custom_auth_example(self): - # from custom_auth_example import CustomAuthExample - # pass - def Xtest_cypher_error_example(self): from cypher_error_example import CypherErrorExample From eb0cc9de28b610803d48688de9689105d8ffbcd8 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Fri, 21 Apr 2017 11:08:06 +0200 Subject: [PATCH 03/10] Implement the service unavailable test. --- test/examples/service_unavailable_example.py | 33 ++++++-------------- test/examples/test_examples.py | 12 +++++-- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/test/examples/service_unavailable_example.py b/test/examples/service_unavailable_example.py index 83bbf6499..60216c294 100644 --- a/test/examples/service_unavailable_example.py +++ b/test/examples/service_unavailable_example.py @@ -19,33 +19,20 @@ # limitations under the License. # tag::service-unavailable-import[] -from neo4j.v1 import GraphDatabase +from neo4j.v1 import GraphDatabase, ServiceUnavailable +from base_application import BaseApplication # end::service-unavailable-import[] -class ServiceUnavailableExample: +class ServiceUnavailableExample(BaseApplication): def __init__(self, uri, user, password): - self._driver = GraphDatabase.driver( uri, auth=(user, password), Config.build().withMaxTransactionRetryTime( 3, SECONDS ).withLogging( DEV_NULL_LOGGING ).toConfig() ) - - def close(self): - self._driver.close(); + super().__init__(uri, user, password) # tag::service-unavailable[] def addItem(self): - try ( Session session = driver.session() ) - { - return session.writeTransaction( new TransactionWork() - { - @Override - public Boolean execute( Transaction tx ) - { - tx.run( "CREATE (a:Item)" ); - return true; - } - } ); - } - catch ( ServiceUnavailableException ex ) - { - return false; - } - } + try: + with self._driver.session() as session: + 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/test_examples.py b/test/examples/test_examples.py index 52a42cdac..919230bed 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -106,9 +106,15 @@ def test_result_retain_example(self): self.assertEqual(employee_count, 2) - # def test_service_unavailable_example(self): - # from service_unavailable_example import ServiceUnavailableExample - # pass + def test_service_unavailable_example(self): + from service_unavailable_example import ServiceUnavailableExample + + example = ServiceUnavailableExample(self.bolt_uri, self.user, self.password) + ExamplesTest._stop_server() + + self.assertFalse(example.addItem()) + + ExamplesTest._start_server() def test_session_example(self): from session_example import SessionExample From c42a822818370dfadc3bd6bb5f9cc12d39fffba7 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Fri, 21 Apr 2017 12:00:11 +0200 Subject: [PATCH 04/10] `clock()` gives CPU time, which is incorrect here. --- neo4j/v1/api.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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): From cd700cd31cc90fce0952ffb19a596eb112134497 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Fri, 21 Apr 2017 12:00:50 +0200 Subject: [PATCH 05/10] Fix the ServiceUnavailable test. --- test/examples/service_unavailable_example.py | 6 +++--- test/examples/test_examples.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/examples/service_unavailable_example.py b/test/examples/service_unavailable_example.py index 60216c294..73124099f 100644 --- a/test/examples/service_unavailable_example.py +++ b/test/examples/service_unavailable_example.py @@ -29,10 +29,10 @@ def __init__(self, uri, user, password): # tag::service-unavailable[] def addItem(self): + session = self._driver.session() try: - with self._driver.session() as session: - session.write_transaction(lambda tx: tx.run("CREATE (a:Item)")) - return True + 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/test_examples.py b/test/examples/test_examples.py index 919230bed..0447b99d9 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -110,11 +110,11 @@ def test_service_unavailable_example(self): from service_unavailable_example import ServiceUnavailableExample example = ServiceUnavailableExample(self.bolt_uri, self.user, self.password) - ExamplesTest._stop_server() + ExamplesTest.controller.stop() self.assertFalse(example.addItem()) - ExamplesTest._start_server() + ExamplesTest.controller.start() def test_session_example(self): from session_example import SessionExample From 72b18011647c623912601fa8e892216cb07a470f Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Fri, 21 Apr 2017 15:48:05 +0200 Subject: [PATCH 06/10] Separating this ensures it won't break other tests. --- test/examples/test_examples.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index 0447b99d9..95a74c0de 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -106,16 +106,6 @@ def test_result_retain_example(self): self.assertEqual(employee_count, 2) - def test_service_unavailable_example(self): - from service_unavailable_example import ServiceUnavailableExample - - example = ServiceUnavailableExample(self.bolt_uri, self.user, self.password) - ExamplesTest.controller.stop() - - self.assertFalse(example.addItem()) - - ExamplesTest.controller.start() - def test_session_example(self): from session_example import SessionExample @@ -154,3 +144,14 @@ def person_count(self, name): 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()) From b906fe55a6558dbbeb707ee7b0c0d16dd1e3b1b2 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Fri, 21 Apr 2017 15:48:39 +0200 Subject: [PATCH 07/10] If the server shuts down, self._connection is None. --- neo4j/v1/session.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 From 1bb13682f7d424196ba2651f9c32ee845b1fcf1f Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Fri, 21 Apr 2017 15:48:55 +0200 Subject: [PATCH 08/10] Clean up. --- test/examples/hello_world_example.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/examples/hello_world_example.py b/test/examples/hello_world_example.py index cf86b2344..cb2b31e4d 100644 --- a/test/examples/hello_world_example.py +++ b/test/examples/hello_world_example.py @@ -20,15 +20,13 @@ # tag::hello-world-import[] from neo4j.v1 import GraphDatabase +from base_application import BaseApplication # end::hello-world-import[] # tag::hello-world[] -class HelloWorldExample: +class HelloWorldExample(BaseApplication): def __init__(self, uri, user, password): - self._driver = GraphDatabase.driver(uri, auth=(user, password)) - - def close(self): - self._driver.close() + super().__init__(uri, user, password) def _create_and_return_greeting(self, tx, message): record_list = list(tx.run("CREATE (a:Greeting) " + From 56e407f72265bac59f9c20d1c07eb210531fdfdf Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Wed, 26 Apr 2017 14:33:20 +0200 Subject: [PATCH 09/10] Support both python2 and python3. --- .../autocommit_transaction_example.py | 2 +- test/examples/base_application.py | 2 +- test/examples/cypher_error_example.py | 2 +- test/examples/hello_world_example.py | 2 +- .../read_write_transaction_example.py | 2 +- test/examples/result_consume_example.py | 2 +- test/examples/result_retain_example.py | 2 +- test/examples/service_unavailable_example.py | 2 +- test/examples/session_example.py | 2 +- test/examples/test_examples.py | 27 ++++++++++++++++--- test/examples/transaction_function_example.py | 2 +- 11 files changed, 33 insertions(+), 14 deletions(-) diff --git a/test/examples/autocommit_transaction_example.py b/test/examples/autocommit_transaction_example.py index dcfb896a7..71525d078 100644 --- a/test/examples/autocommit_transaction_example.py +++ b/test/examples/autocommit_transaction_example.py @@ -25,7 +25,7 @@ class AutocommitTransactionExample(BaseApplication): def __init__(self, uri, user, password): - super().__init__(uri, user, password) + super(AutocommitTransactionExample, self).__init__(uri, user, password) # tag::autocommit-transaction[] def add_person(self, name): diff --git a/test/examples/base_application.py b/test/examples/base_application.py index 8c2dc0cd5..5d0acab85 100644 --- a/test/examples/base_application.py +++ b/test/examples/base_application.py @@ -20,7 +20,7 @@ from neo4j.v1 import GraphDatabase -class BaseApplication: +class BaseApplication(object): def __init__(self, uri, user, password): self._driver = GraphDatabase.driver( uri, auth=( user, password ) ) diff --git a/test/examples/cypher_error_example.py b/test/examples/cypher_error_example.py index 45f5a4f25..690184304 100644 --- a/test/examples/cypher_error_example.py +++ b/test/examples/cypher_error_example.py @@ -25,7 +25,7 @@ class CypherErrorExample(BaseApplication): def __init__(self, uri, user, password): - super().__init__(uri, user, password) + super(CypherErrorExample, self).__init__(uri, user, password) # FIXME: this doesn't work because read_transaction behaves # differently than in Java, so this throws a ClientError diff --git a/test/examples/hello_world_example.py b/test/examples/hello_world_example.py index cb2b31e4d..d9e3df8be 100644 --- a/test/examples/hello_world_example.py +++ b/test/examples/hello_world_example.py @@ -26,7 +26,7 @@ # tag::hello-world[] class HelloWorldExample(BaseApplication): def __init__(self, uri, user, password): - super().__init__(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) " + diff --git a/test/examples/read_write_transaction_example.py b/test/examples/read_write_transaction_example.py index d7d7a4784..ec5bef984 100644 --- a/test/examples/read_write_transaction_example.py +++ b/test/examples/read_write_transaction_example.py @@ -25,7 +25,7 @@ class ReadWriteTransactionExample(BaseApplication): def __init__(self, uri, user, password): - super().__init__(uri, user, password) + super(ReadWriteTransactionExample, self).__init__(uri, user, password) # tag::read-write-transaction[] def add_person(self, name): diff --git a/test/examples/result_consume_example.py b/test/examples/result_consume_example.py index ba76abe67..02ffc2487 100644 --- a/test/examples/result_consume_example.py +++ b/test/examples/result_consume_example.py @@ -25,7 +25,7 @@ class ResultConsumeExample(BaseApplication): def __init__(self, uri, user, password): - super().__init__(uri, user, password) + super(ResultConsumeExample, self).__init__(uri, user, password) # tag::result-consume[] def get_people(self): diff --git a/test/examples/result_retain_example.py b/test/examples/result_retain_example.py index a8ffab5a7..ddf375357 100644 --- a/test/examples/result_retain_example.py +++ b/test/examples/result_retain_example.py @@ -25,7 +25,7 @@ class ResultRetainExample(BaseApplication): def __init__(self, uri, user, password): - super().__init__(uri, user, password) + super(ResultRetainExample, self).__init__(uri, user, password) # tag::result-retain[] def add_employees(self, company_name): diff --git a/test/examples/service_unavailable_example.py b/test/examples/service_unavailable_example.py index 73124099f..7dba85f08 100644 --- a/test/examples/service_unavailable_example.py +++ b/test/examples/service_unavailable_example.py @@ -25,7 +25,7 @@ class ServiceUnavailableExample(BaseApplication): def __init__(self, uri, user, password): - super().__init__(uri, user, password) + super(ServiceUnavailableExample, self).__init__(uri, user, password) # tag::service-unavailable[] def addItem(self): diff --git a/test/examples/session_example.py b/test/examples/session_example.py index 78acef22d..612416cd6 100644 --- a/test/examples/session_example.py +++ b/test/examples/session_example.py @@ -24,7 +24,7 @@ class SessionExample(BaseApplication): def __init__(self, uri, user, password): - super().__init__(uri, user, password) + super(SessionExample, self).__init__(uri, user, password) # tag::session[] def do_work(self): diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index 95a74c0de..4fac55b4c 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -20,6 +20,27 @@ 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): @@ -65,12 +86,10 @@ def test_driver_lifecycle_example(self): self.assertIsInstance(example, DriverLifecycleExample) def test_hello_world_example(self): - import io - from contextlib import redirect_stdout from hello_world_example import HelloWorldExample - f = io.StringIO() - with redirect_stdout(f): + f = get_string_io() + with stdout_redirector(f): example = HelloWorldExample(self.bolt_uri, self.user, self.password) example.print_greeting("hello, world") example.close() diff --git a/test/examples/transaction_function_example.py b/test/examples/transaction_function_example.py index f50f105e7..29893a2db 100644 --- a/test/examples/transaction_function_example.py +++ b/test/examples/transaction_function_example.py @@ -25,7 +25,7 @@ class TransactionFunctionExample(BaseApplication): def __init__(self, uri, user, password): - super().__init__(uri, user, password) + super(TransactionFunctionExample, self).__init__(uri, user, password) # tag::transaction-function[] def add_person(self, name): From a498cd548b29f5373da8643ddefbf2e103b6e369 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Wed, 26 Apr 2017 14:50:27 +0200 Subject: [PATCH 10/10] Fix the last test. --- test/examples/cypher_error_example.py | 7 ++----- test/examples/test_examples.py | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/test/examples/cypher_error_example.py b/test/examples/cypher_error_example.py index 690184304..ea75c00f0 100644 --- a/test/examples/cypher_error_example.py +++ b/test/examples/cypher_error_example.py @@ -27,13 +27,10 @@ class CypherErrorExample(BaseApplication): def __init__(self, uri, user, password): super(CypherErrorExample, self).__init__(uri, user, password) - # FIXME: this doesn't work because read_transaction behaves - # differently than in Java, so this throws a ClientError - # tag::cypher-error[] def get_employee_number(self, name): - with self._driver.session() as session: - return session.read_transaction(lambda tx: self.select_employee(tx, name)) + session = self._driver.session() + session.read_transaction(lambda tx: self.select_employee(tx, name)) def select_employee(self, tx, name): try: diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index 4fac55b4c..564ab95b5 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -68,14 +68,21 @@ def test_config_unencrypted_example(self): self.assertIsInstance(example, ConfigUnencryptedExample) - def Xtest_cypher_error_example(self): + def test_cypher_error_example(self): from cypher_error_example import CypherErrorExample - example = CypherErrorExample(self.bolt_uri, self.user, self.password) - employee_number = example.get_employee_number('Alice') - - # FIXME: also check the error output like in the Java example - self.assertEqual(employee_number, -1) + 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