diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..32e71361 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,14 @@ +[run] +include = rethinkdb/* + +[report] +exclude_lines = + pragma: no cover + + def __unicode__ + def __repr__ + +omit = + rethinkdb/version.py + +show_missing = True diff --git a/.editorconfig b/.editorconfig index e41cc6f2..d80ae855 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,4 @@ -# Copyright 2018 RebirthDB +# Copyright 2018 RethinkDB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..7b666369 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: rethinkdb +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..9e0a7bb3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,27 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug, not qualified + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. TODO + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**System info** + - OS: [e.g. macOS Mojave 10.14.3] + - RethinkDB Version: [e.g. 2.4.0] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..0512b489 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement, not qualified, question + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..fc4a2e02 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,14 @@ +**Reason for the change** +If applicable, link the related issue/bug report or write down in few sentences the motivation. + +**Description** +A clear and concise description of what did you changed and why. + +**Code examples** +If applicable, add code examples to help explain your changes. + +**Checklist** +- [ ] I have read and agreed to the [RethinkDB Contributor License Agreement](http://rethinkdb.com/community/cla/) + +**References** +Anything else related to the change e.g. documentations, RFCs, etc. diff --git a/.gitignore b/.gitignore index e49ba85d..72d80ecc 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ coverage.xml .python-version # Environments +*.pid .env .venv env/ @@ -64,10 +65,11 @@ env.bak/ venv.bak/ virtualenv/ -# RebirthDB -convert_protofile.py -rebirthdb/ql2_pb2.py -rebirthdb/*.proto +# RethinkDB +rethinkdb/ql2_pb2.py +rethinkdb/*.proto +rethinkdb_data/ +rebirthdb_data/ # Editors .vscode/ diff --git a/.travis.yml b/.travis.yml index d542aa9f..ecb5857a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,27 +1,38 @@ -sudo: false +cache: pip +dist: xenial language: python +sudo: required python: - "2.7" - - "3.4" - "3.5" - "3.6" + - "3.7" + - "3.8" + +allow_failure: + - python: "3.8" install: - pip install -r requirements.txt - -jobs: - include: - - stage: upload_coverage - python: "3.6" - script: make upload-coverage - - # - stage: integration_test - # if: branch = master - # script: make test-integration + - pip freeze before_script: - make prepare - + - make install-db + script: - - make test-unit + - make test-ci + +after_success: + - make upload-coverage + +deploy: + provider: script + script: make upload-pypi + on: + python: 3.8 + tags: true + +notifications: + email: false diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..9c628288 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,71 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behaviour that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behaviour by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behaviour and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behaviour. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behaviour may be +reported by contacting the project team at open@rethinkdb.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the Contributor Covenant, version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..e8c48beb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,45 @@ +# Contributing + +Contributions are welcome, and they are greatly appreciated! Every little bit helps! You can contribute in many ways, not limited to this document. + +## Types of Contributions + +### Report Bugs + +First of all, please check that the bug is not reported yet. If that's already reported then upvote the existing bug instead of opening a new bug report. + +Report bugs at https://github.com/rethinkdb/rethinkdb-python/issues. If you are reporting a bug, please include: + +- Your operating system name and version. +- Any details about your local setup that might be helpful in troubleshooting. +- Detailed steps to reproduce the bug. + +### Fix Bugs + +Look through the GitHub issues for bugs. Anything tagged with "bug", "good first issue" and "help wanted" is open to whoever wants to implement it. + +### Implement Features + +Look through the GitHub issues for features. Anything tagged with "enhancement", "good first issue" and "help wanted" is open to whoever wants to implement it. In case you added a new Rule or Precondition, do not forget to add them to the docs as well. + +### Write Documentation + +RethinkDB could always use more documentation, whether as part of the official docs, in docstrings, or even on the web in blog posts, articles, and such. To extend the documentation on the website, visit the [www](https://github.com/rethinkdb/www) repo. For extending the docs, you can check the [docs](https://github.com/rethinkdb/docs) repo. + +### Submit A Feature + +First of all, please check that the feature request is not reported yet. If that's already reported then upvote the existing request instead of opening a new one. + +If you are proposing a feature: + +- Check if there is an opened feature request for the same idea. +- Explain in detail how it would work. +- Keep the scope as narrow as possible, to make it easier to implement. +- Remember that this is an open-source project, and that contributions are welcome :) + +## Pull Request Guidelines + +Before you submit a pull request, check that it meets these guidelines: + +1. The pull request should include tests (if applicable) +2. If the pull request adds functionality, the docs should be updated too. diff --git a/LICENSE b/LICENSE index c17a2c5e..261eeb9e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,201 @@ -Copyright 2018 RebirthDB + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -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 + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - http://www.apache.org/licenses/LICENSE-2.0 + 1. Definitions. -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. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..c41b03bc --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,8 @@ +include LICENSE +include *.txt +include Makefile +include pytest.ini +include .coveragerc +recursive-include scripts *.py +recursive-include scripts *.sh +recursive-include tests *.py diff --git a/Makefile b/Makefile index 3897ec0f..23d0dbde 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# Copyright 2018 RebirthDB +# Copyright 2018 RethinkDB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,19 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -.PHONY: default help clean prepare package publish +.PHONY: default help test-unit test-integration test-remote upload-coverage upload-pypi clean prepare -PACKAGE_NAME = rebirthdb - -BUILD_DIR = ./build -PACKAGE_DIR = ${BUILD_DIR}/package +PACKAGE_NAME = rethinkdb PROTO_FILE_NAME = ql2.proto -PROTO_FILE_URL = https://raw.githubusercontent.com/RebirthDB/rebirthdb/next/src/rdb_protocol/${PROTO_FILE_NAME} +PROTO_FILE_URL = https://raw.githubusercontent.com/rethinkdb/rethinkdb/next/src/rdb_protocol/${PROTO_FILE_NAME} TARGET_PROTO_FILE = ${PACKAGE_NAME}/${PROTO_FILE_NAME} -FILE_CONVERTER_NAME = convert_protofile.py -FILE_CONVERTER_URL = https://raw.githubusercontent.com/RebirthDB/rebirthdb/next/scripts/${FILE_CONVERTER_NAME} +FILE_CONVERTER_NAME = ./scripts/convert_protofile.py +REMOTE_TEST_SETUP_NAME = ./scripts/prepare_remote_test.py CONVERTED_PROTO_FILE_NAME = ql2_pb2.py TARGET_CONVERTED_PROTO_FILE = ${PACKAGE_NAME}/${CONVERTED_PROTO_FILE_NAME} @@ -35,46 +32,50 @@ default: help help: @echo "Usage:" @echo - @echo " make help Print this help message" - @echo " make test-unit Run unit tests" - @echo " make test-integration Run integration tests" - @echo " make upload-coverage Upload unit test coverage" - @echo " make clean Cleanup source directory" - @echo " make prepare Prepare ${PACKAGE_NAME} for build" - @echo " make package Build ${PACKAGE_NAME} package" - @echo " make publish Publish ${PACKAGE_NAME} package on PyPi" + @echo " make help Print this help message" + @echo " make test-unit Run unit tests" + @echo " make test-integration Run integration tests" + @echo " make test-integration-2.4 Run integration tests" + @echo " make test-remote Run tests on digital ocean" + @echo " make upload-coverage Upload unit test coverage" + @echo " make upload-pypi Release ${PACKAGE_NAME} package to PyPi" + @echo " make clean Cleanup source directory" + @echo " make prepare Prepare ${PACKAGE_NAME} for build" test-unit: - pytest -m unit + pytest -v -m unit test-integration: - pytest -m integration + @rethinkdb& + pytest -v -m integration + @killall rethinkdb + +test-ci: + @rethinkdb& + pytest -v --cov rethinkdb --cov-report xml + @killall rethinkdb + +test-remote: + python ${REMOTE_TEST_SETUP_NAME} pytest -m integration + +install-db: + @sh scripts/install-db.sh upload-coverage: - pytest -m unit --cov rebirthdb --cov-report xml - python-codacy-coverage -r coverage.xml + @sh scripts/upload-coverage.sh + +upload-pypi: prepare + @sh scripts/upload-pypi.sh clean: @rm -rf \ - ${FILE_CONVERTER_NAME} \ ${TARGET_PROTO_FILE} \ ${TARGET_CONVERTED_PROTO_FILE} \ - ${BUILD_DIR} \ - .tox \ .pytest_cache \ .eggs \ + .dist \ *.egg-info prepare: curl -qo ${TARGET_PROTO_FILE} ${PROTO_FILE_URL} - curl -qo ${FILE_CONVERTER_NAME} ${FILE_CONVERTER_URL} - python ./${FILE_CONVERTER_NAME} -l python -i ${TARGET_PROTO_FILE} -o ${TARGET_CONVERTED_PROTO_FILE} - rsync -av ./ ${BUILD_DIR} --filter=':- .gitignore' - cp ${TARGET_PROTO_FILE} ${BUILD_DIR}/${PACKAGE_NAME} - -package: prepare - cd ${BUILD_DIR} && python ./setup.py sdist --dist-dir=$(abspath ${PACKAGE_DIR}) - -publish: - cd ${BUILD_DIR} && python ./setup.py register upload - + python ${FILE_CONVERTER_NAME} -l python -i ${TARGET_PROTO_FILE} -o ${TARGET_CONVERTED_PROTO_FILE} diff --git a/README.md b/README.md index 870afc52..049c1e65 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,50 @@ -# RebirthDB Python driver -[![Build Status](https://travis-ci.org/RebirthDB/rebirthdb-python.svg?branch=master)](https://travis-ci.org/RebirthDB/rebirthdb-python) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/2b5231a6f90a4a1ba2fc795f8466bbe4)](https://www.codacy.com/app/RebirthDB/rebirthdb-python?utm_source=github.com&utm_medium=referral&utm_content=RebirthDB/rebirthdb-python&utm_campaign=Badge_Grade) +# RethinkDB Python driver +[![PyPI version](https://badge.fury.io/py/rethinkdb.svg)](https://badge.fury.io/py/rethinkdb) [![Build Status](https://travis-ci.org/rethinkdb/rethinkdb-python.svg?branch=master)](https://travis-ci.org/rethinkdb/rethinkdb-python) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/2b5231a6f90a4a1ba2fc795f8466bbe4)](https://www.codacy.com/app/rethinkdb/rethinkdb-python?utm_source=github.com&utm_medium=referral&utm_content=rethinkdb/rethinkdb-python&utm_campaign=Badge_Grade) [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/2b5231a6f90a4a1ba2fc795f8466bbe4)](https://www.codacy.com/app/rethinkdb/rethinkdb-python?utm_source=github.com&utm_medium=referral&utm_content=rethinkdb/rethinkdb-python&utm_campaign=Badge_Coverage) ## Overview -### What is RebirthDB? -RebirthDB is the fork of RethinkDB which is the first open-source scalable database built for realtime applications. It exposes a new database access model -- instead of polling for changes, the developer can tell the database to continuously push updated query results to applications in realtime. RebirthDB allows developers to build scalable realtime apps in a fraction of the time with less effort. +### What is RethinkDB? +RethinkDB is the first open-source scalable database built for realtime applications. It exposes a new database access model -- instead of polling for changes, the developer can tell the database to continuously push updated query results to applications in realtime. RethinkDB allows developers to build scalable realtime apps in a fraction of the time with less effort. ## Installation ```bash -$ pip install rebirthdb +$ pip install rethinkdb ``` *Note: this package is the extracted driver of RethinkDB's original python driver.* ## Quickstart -The main difference with the previous driver (except the name of the package) is we are **not** importing RebirthDB as `r`. If you would like to use `RebirthDB`'s python driver as a drop in replacement, you should do the following: +The main difference with the previous driver (except the name of the package) is we are **not** importing RethinkDB as `r`. If you would like to use `RethinkDB`'s python driver as a drop in replacement, you should do the following: ```python -from rebirthdb import RebirthDB +from rethinkdb import r -r = RebirthDB() connection = r.connect(db='test') ``` -## Example -Create a table, populate with data, and get every document. +## Blocking and Non-blocking I/O +This driver supports blocking I/O (i.e. standard Python sockets) as well as +non-blocking I/O through multiple async frameworks: + +* [Asyncio](https://docs.python.org/3/library/asyncio.html) +* [Gevent](http://www.gevent.org/) +* [Tornado](https://www.tornadoweb.org/en/stable/) +* [Trio](https://trio.readthedocs.io/en/latest/) +* [Twisted](https://twistedmatrix.com/trac/) + +The following examples demonstrate how to use the driver in each mode. + +### Default mode (blocking I/O) +The driver's default mode of operation is to use blocking I/O, i.e. standard Python +sockets. This example shows how to create a table, populate with data, and get every +document. ```python -from rebirthdb import RebirthDB +from rethinkdb import r -r = RebirthDB() connection = r.connect(db='test') r.table_create('marvel').run(connection) + marvel_heroes = r.table('marvel') marvel_heroes.insert({ 'id': 1, @@ -43,11 +56,201 @@ for hero in marvel_heroes.run(connection): print(hero['name']) ``` +### Asyncio mode +Asyncio mode is compatible with Python ≥ 3.5. + +```python +import asyncio +from rethinkdb import r + +async def main(): + async with await r.connect(db='test') as connection: + await r.table_create('marvel').run(connection) + + marvel_heroes = r.table('marvel') + await marvel_heroes.insert({ + 'id': 1, + 'name': 'Iron Man', + 'first_appearance': 'Tales of Suspense #39' + }).run(connection) + + # "async for" is supported in Python ≥ 3.6. In earlier versions, you should + # call "await cursor.next()" in a loop. + cursor = await marvel_heroes.run(connection) + async for hero in cursor: + print(hero['name']) + # The `with` block performs `await connection.close(noreply_wait=False)`. + +r.set_loop_type('asyncio') + +# "asyncio.run" was added in Python 3.7. In earlier versions, you +# might try asyncio.get_event_loop().run_until_complete(main()). +asyncio.run(main()) +``` + +### Gevent mode + +```python +import gevent +from rethinkdb import r + +def main(): + r.set_loop_type('gevent') + connection = r.connect(db='test') + + r.table_create('marvel').run(connection) + + marvel_heroes = r.table('marvel') + marvel_heroes.insert({ + 'id': 1, + 'name': 'Iron Man', + 'first_appearance': 'Tales of Suspense #39' + }).run(connection) + + for hero in marvel_heroes.run(connection): + print(hero['name']) + +gevent.joinall([gevent.spawn(main)]) +``` + +### Tornado mode +Tornado mode is compatible with Tornado < 5.0.0. Tornado 5 is not supported. + +```python +from rethinkdb import r +from tornado import gen +from tornado.ioloop import IOLoop + +@gen.coroutine +def main(): + r.set_loop_type('tornado') + connection = yield r.connect(db='test') + + yield r.table_create('marvel').run(connection) + + marvel_heroes = r.table('marvel') + yield marvel_heroes.insert({ + 'id': 1, + 'name': 'Iron Man', + 'first_appearance': 'Tales of Suspense #39' + }).run(connection) + + cursor = yield marvel_heroes.run(connection) + while (yield cursor.fetch_next()): + hero = yield cursor.next() + print(hero['name']) + +IOLoop.current().run_sync(main) +``` + +### Trio mode + +```python +from rethinkdb import r +import trio + +async def main(): + r.set_loop_type('trio') + async with trio.open_nursery() as nursery: + async with r.open(db='test', nursery=nursery) as conn: + await r.table_create('marvel').run(conn) + marvel_heroes = r.table('marvel') + await marvel_heroes.insert({ + 'id': 1, + 'name': 'Iron Man', + 'first_appearance': 'Tales of Suspense #39' + }).run(conn) + + # "async for" is supported in Python ≥ 3.6. In earlier versions, you should + # call "await cursor.next()" in a loop. + cursor = await marvel_heroes.run(conn) + async with cursor: + async for hero in cursor: + print(hero['name']) + +trio.run(main) +``` + +The Trio mode also supports a database connection pool. You can modify the example above +as follows: + +```python +db_pool = r.ConnectionPool(db='test', nursery=nursery) +async with db_pool.connection() as conn: + ... +await db_pool.close() +``` + +### Twisted mode + +```python +from rethinkdb import r +from twisted.internet import reactor, defer + +@defer.inlineCallbacks +def main(): + r.set_loop_type('twisted') + connection = yield r.connect(db='test') + + yield r.table_create('marvel').run(connection) + + marvel_heroes = r.table('marvel') + yield marvel_heroes.insert({ + 'id': 1, + 'name': 'Iron Man', + 'first_appearance': 'Tales of Suspense #39' + }).run(connection) + + cursor = yield marvel_heroes.run(connection) + while (yield cursor.fetch_next()): + hero = yield cursor.next() + print(hero['name']) + +main().addCallback(lambda d: print("stopping") or reactor.stop()) +reactor.run() +``` + +## Misc +To help the migration from rethinkdb<2.4 we introduced a shortcut which can easily replace the old `import rethinkdb as r` import with `from rethinkdb import r`. + ## Run tests -To ensure python driver works with python 2.7, 3.4, 3.5, 3.6 we are using `tox` and `pytest`. For testing (depending on what you would like to test) you can run `tox` or `pytest`. +In the `Makefile` you can find three different test commands: `test-unit`, `test-integration` and `test-remote`. As RethinkDB has dropped the support of Windows, we would like to ensure that those of us who are using Windows for development can still contribute. Because of this, we support running integration tests against Digital Ocean Droplets as well. + +Before you run any test, make sure that you install the requirements. +```bash +$ pip install -r requirements.txt +$ make prepare +``` + +### Running unit tests +```bash +$ make test-unit +``` + +### Running integration tests +*To run integration tests locally, make sure you intstalled RethinkDB* +```bash +$ make test-integration +``` + +### Running remote integration tests +*To run the remote tests, you need to have a Digital Ocean account and an API key.* + +Remote test will create a new temporary SSH key and a Droplet for you until the tests are finished. -## New features -Github's Issue tracker is **ONLY** used for reporting bugs. NO NEW FEATURE ACCEPTED! Use [spectrum](https://spectrum.chat/rebirthdb) for supporting features. +**Available environment variables** + +| Variable name | Default value | +|---------------|---------------| +| DO_TOKEN | N/A | +| DO_SIZE | 512MB | +| DO_REGION | sfo2 | + +```bash +$ pip install paramiko python-digitalocean +$ export DO_TOKEN= +$ make test-remote +``` ## Contributing Hurray! You reached this section which means, that you would like to contribute. Please read our contributing guide lines and feel free to open a pull request. diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..602e59d0 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,8 @@ +[pytest] +python_files = test_*.py +markers = + unit: Run unit tests + integration: Run integration tests + trio: Run trio related tests + tornado: Run tornado related tests + asyncio: Run asyncio related tests \ No newline at end of file diff --git a/rebirthdb/__init__.py b/rebirthdb/__init__.py deleted file mode 100644 index ec94ac84..00000000 --- a/rebirthdb/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2018 RebirthDB -# -# 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 rebirthdb import errors, version - - -try: - import __builtin__ as builtins # Python 2 -except ImportError: - import builtins # Python 3 - - -__all__ = ['r', 'rebirthdb'] + errors.__all__ -__version__ = version.version - - -# The builtins here defends against re-importing something obscuring `object`. - - -class RebirthDB(builtins.object): - def __init__(self): - super(RebirthDB, self).__init__() - - from rebirthdb import _dump, _export, _import, _index_rebuild, _restore, ast, query, net - - self._dump = _dump - self._export = _export - self._import = _import - self._index_rebuild = _index_rebuild - self._restore = _restore - - net.Connection._r = self - - for module in (net, query, ast, errors): - for functionName in module.__all__: - setattr(self, functionName, getattr(module, functionName)) diff --git a/rebirthdb/_index_rebuild.py b/rebirthdb/_index_rebuild.py deleted file mode 100755 index 3500057e..00000000 --- a/rebirthdb/_index_rebuild.py +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2018 RebirthDB -# -# 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. -# -# This file incorporates work covered by the following copyright: -# Copyright 2010-2016 RethinkDB, all rights reserved. - - -"""'rebirthdb index-rebuild' recreates outdated secondary indexes in a cluster. - This should be used after upgrading to a newer version of rebirthdb. There - will be a notification in the web UI if any secondary indexes are out-of-date.""" - -from __future__ import print_function - -import sys -import time -import traceback - -from rebirthdb import query, utils_common - -usage = "rebirthdb index-rebuild [-c HOST:PORT] [-n NUM] [-r (DB | DB.TABLE)] [--tls-cert FILENAME] [-p] " \ - "[--password-file FILENAME]..." -help_epilog = ''' -FILE: the archive file to restore data from - -EXAMPLES: -rebirthdb index-rebuild -c mnemosyne:39500 - rebuild all outdated secondary indexes from the cluster through the host 'mnemosyne', - one at a time - -rebirthdb index-rebuild -r test -r production.users -n 5 - rebuild all outdated secondary indexes from a local cluster on all tables in the - 'test' database as well as the 'production.users' table, five at a time -''' - -# Prefix used for indexes that are being rebuilt -temp_index_prefix = '$reql_temp_index$_' - - -def parse_options(argv, prog=None): - parser = utils_common.CommonOptionsParser(usage=usage, epilog=help_epilog, prog=prog) - - parser.add_option( - "-r", - "--rebuild", - dest="db_table", - metavar="DB|DB.TABLE", - default=[], - help="databases or tables to rebuild indexes on (default: all, may be specified multiple times)", - action="append", - type="db_table") - parser.add_option( - "-n", - dest="concurrent", - metavar="NUM", - default=1, - help="concurrent indexes to rebuild (default: 1)", - type="pos_int") - parser.add_option("--force", dest="force", action="store_true", default=False, help="rebuild non-outdated indexes") - - options, args = parser.parse_args(argv) - - # Check validity of arguments - if len(args) != 0: - parser.error("Error: No positional arguments supported. Unrecognized option '%s'" % args[0]) - - return options - - -def rebuild_indexes(options): - - # flesh out options.db_table - if not options.db_table: - options.db_table = [ - utils_common.DbTable(x['db'], x['name']) for x in - options.retryQuery('all tables', query.db('rebirthdb').table('table_config').pluck(['db', 'name'])) - ] - else: - for db_table in options.db_table[:]: # work from a copy - if not db_table[1]: - options.db_table += [ - utils_common.DbTable(db_table[0], x) for x in options.retryQuery('table list of %s' % db_table[0], - query.db(db_table[0]).table_list()) - ] - del options.db_table[db_table] - - # wipe out any indexes with the temp_index_prefix - for db, table in options.db_table: - for index in options.retryQuery('list indexes on %s.%s' % (db, table), query.db(db).table(table).index_list()): - if index.startswith(temp_index_prefix): - options.retryQuery( - 'drop index: %s.%s:%s' % - (db, - table, - index), - query.db( - index['db']).table( - index['table']).index_drop( - index['name'])) - - # get the list of indexes to rebuild - indexes_to_build = [] - for db, table in options.db_table: - indexes = None - if not options.force: - indexes = options.retryQuery('get outdated indexes from %s.%s' % (db, table), query.db( - db).table(table).index_status().filter({'outdated': True}).get_field('index')) - else: - indexes = options.retryQuery('get all indexes from %s.%s' % - (db, table), query.db(db).table(table).index_status().get_field('index')) - for index in indexes: - indexes_to_build.append({'db': db, 'table': table, 'name': index}) - - # rebuild selected indexes - - total_indexes = len(indexes_to_build) - indexes_completed = 0 - progress_ratio = 0.0 - highest_progress = 0.0 - indexes_in_progress = [] - - if not options.quiet: - print("Rebuilding %d index%s: %s" % (total_indexes, 'es' if total_indexes > 1 else '', - ", ".join(["`%(db)s.%(table)s:%(name)s`" % i for i in indexes_to_build]))) - - while len(indexes_to_build) > 0 or len(indexes_in_progress) > 0: - # Make sure we're running the right number of concurrent index rebuilds - while len(indexes_to_build) > 0 and len(indexes_in_progress) < options.concurrent: - index = indexes_to_build.pop() - indexes_in_progress.append(index) - index['temp_name'] = temp_index_prefix + index['name'] - index['progress'] = 0 - index['ready'] = False - - existingIndexes = dict( - (x['index'], - x['function']) for x in options.retryQuery( - 'existing indexes', - query.db( - index['db']).table( - index['table']).index_status().pluck( - 'index', - 'function'))) - - if index['name'] not in existingIndexes: - raise AssertionError('{index_name} is not part of existing indexes {indexes}'.format( - index_name=index['name'], - indexes=', '.join(existingIndexes) - )) - - if index['temp_name'] not in existingIndexes: - options.retryQuery('create temp index: %(db)s.%(table)s:%(name)s' % index, query.db(index['db']).table( - index['table']).index_create(index['temp_name'], existingIndexes[index['name']])) - - # Report progress - highest_progress = max(highest_progress, progress_ratio) - if not options.quiet: - utils_common.print_progress(highest_progress) - - # Check the status of indexes in progress - progress_ratio = 0.0 - for index in indexes_in_progress: - status = options.retryQuery( - "progress `%(db)s.%(table)s` index `%(name)s`" % index, - query.db(index['db']).table(index['table']).index_status(index['temp_name']).nth(0) - ) - if status['ready']: - index['ready'] = True - options.retryQuery( - "rename `%(db)s.%(table)s` index `%(name)s`" % - index, - query.db( - index['db']).table( - index['table']).index_rename( - index['temp_name'], - index['name'], - overwrite=True)) - else: - progress_ratio += status.get('progress', 0) / total_indexes - - indexes_in_progress = [index for index in indexes_in_progress if not index['ready']] - indexes_completed = total_indexes - len(indexes_to_build) - len(indexes_in_progress) - progress_ratio += float(indexes_completed) / total_indexes - - if len(indexes_in_progress) == options.concurrent or \ - (len(indexes_in_progress) > 0 and len(indexes_to_build) == 0): - # Short sleep to keep from killing the CPU - time.sleep(0.1) - - # Make sure the progress bar says we're done and get past the progress bar line - if not options.quiet: - utils_common.print_progress(1.0) - print("") - - -def main(argv=None, prog=None): - options = parse_options(argv or sys.argv[1:], prog=prog) - start_time = time.time() - try: - rebuild_indexes(options) - except Exception as ex: - if options.debug: - traceback.print_exc() - if not options.quiet: - print(ex, file=sys.stderr) - return 1 - if not options.quiet: - print("Done (%d seconds)" % (time.time() - start_time)) - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/rebirthdb/docs.py b/rebirthdb/docs.py deleted file mode 100644 index b29f811c..00000000 --- a/rebirthdb/docs.py +++ /dev/null @@ -1,197 +0,0 @@ -# -*- coding: utf-8 -*- -# This file was generated by _scripts/gen_python.py from the rebirthdb documentation in http://github.com/rethinkdb/docs -# hash: "186fb20ea9911710e910acfab0f4f221d59d7c04" - -import rebirthdb - -docsSource = [ - - (rebirthdb.net.Connection.close, b'conn.close(noreply_wait=True)\n\nClose an open connection.\n\nClosing a connection normally waits until all outstanding requests have finished and then frees any open resources associated with the connection. By passing `False` to the `noreply_wait` optional argument, the connection will be closed immediately, possibly aborting any outstanding noreply writes.\n\nA noreply query is executed by passing the `noreply` option to the [run](http://rebirthdb.com/api/python/run/) command, indicating that `run()` should not wait for the query to complete before returning. You may also explicitly wait for a noreply query to complete by using the [noreply_wait](http://rebirthdb.com/api/python/noreply_wait) command.\n\n*Example* Close an open connection, waiting for noreply writes to finish.\n\n conn.close()\n\n*Example* Close an open connection immediately.\n\n conn.close(noreply_wait=False)\n'), - (rebirthdb.connect, b'r.connect(host="localhost", port=28015, db="test", auth_key="", timeout=20) -> connection\nr.connect(host) -> connection\n\nCreate a new connection to the database server. The keyword arguments are:\n\n- `host`: host of the RethinkDB instance. The default value is `localhost`.\n- `port`: the driver port, by default `28015`.\n- `db`: the database used if not explicitly specified in a query, by default `test`.\n- `user`: the user account to connect as (default `admin`).\n- `password`: the password for the user account to connect as (default `\'\'`, empty).\n- `timeout`: timeout period in seconds for the connection to be opened (default `20`).\n- `ssl`: a hash of options to support SSL connections (default `None`). Currently, there is only one option available, and if the `ssl` option is specified, this key is required:\n - `ca_certs`: a path to the SSL CA certificate.\n\nIf the connection cannot be established, a `ReqlDriverError` exception will be thrown.\n\n\n\nThe RethinkDB Python driver includes support for asynchronous connections using Tornado and Twisted. Read the asynchronous connections documentation for more information.\n\n*Example* Open a connection using the default host and port, specifying the default database.\n\n conn = r.connect(db=\'marvel\')\n\n*Example* Open a new connection to the database.\n\n conn = r.connect(host=\'localhost\',\n port=28015,\n db=\'heroes\')\n\n*Example* Open a new connection to the database, specifying a user/password combination for authentication.\n\n conn = r.connect(host=\'localhost\',\n port=28015,\n db=\'heroes\',\n user=\'herofinder\',\n password=\'metropolis\')\n\n*Example* Open a new connection to the database using an SSL proxy.\n\n conn = r.connect(host=\'localhost\',\n port=28015,\n auth_key=\'hunter2\',\n ssl={\'ca_certs\': \'/path/to/ca.crt\'})\n\n*Example* Use a `with` statement to open a connection and pass it to a block. Using this style, the connection will be automatically closed when execution reaches the end of the block.\n\n with r.connect(db=\'marvel\') as conn:\n r.table(\'superheroes\').run(conn)\n'), - (rebirthdb.net.Connection.noreply_wait, b'conn.noreply_wait()\n\n`noreply_wait` ensures that previous queries with the `noreply` flag have been processed\nby the server. Note that this guarantee only applies to queries run on the given connection.\n\n*Example* We have previously run queries with the `noreply` argument set to `True`. Now\nwait until the server has processed them.\n\n conn.noreply_wait()\n\n'), - (rebirthdb, b'r -> r\n\nThe top-level ReQL namespace.\n\n*Example* Setup your top-level namespace.\n\n import rebirthdb as r\n\n'), - (rebirthdb.net.Connection.reconnect, b'conn.reconnect(noreply_wait=True)\n\nClose and reopen a connection.\n\nClosing a connection normally waits until all outstanding requests have finished and then frees any open resources associated with the connection. By passing `False` to the `noreply_wait` optional argument, the connection will be closed immediately, possibly aborting any outstanding noreply writes.\n\nA noreply query is executed by passing the `noreply` option to the [run](http://rebirthdb.com/api/python/run/) command, indicating that `run()` should not wait for the query to complete before returning. You may also explicitly wait for a noreply query to complete by using the [noreply_wait](http://rebirthdb.com/api/python/noreply_wait) command.\n\n*Example* Cancel outstanding requests/queries that are no longer needed.\n\n conn.reconnect(noreply_wait=False)\n'), - (rebirthdb.net.Connection.repl, b"conn.repl()\n\nSet the default connection to make REPL use easier. Allows calling\n`.run()` on queries without specifying a connection.\n\n__Note:__ Avoid using `repl` in application code. RethinkDB connection objects are not thread-safe, and calls to `connect` from multiple threads may change the global connection object used by `repl`. Applications should specify connections explicitly.\n\n*Example* Set the default connection for the REPL, then call\n`run()` without specifying the connection.\n\n r.connect(db='marvel').repl()\n r.table('heroes').run()\n"), - (rebirthdb.ast.RqlQuery.run, b'query.run(conn[, options]) -> cursor\nquery.run(conn[, options]) -> object\n\nRun a query on a connection, returning either a single JSON result or\na cursor, depending on the query.\n\nThe optional arguments are:\n\n- `read_mode`: One of three possible values affecting the consistency guarantee for the query (default: `\'single\'`).\n - `\'single\'` (the default) returns values that are in memory (but not necessarily written to disk) on the primary replica.\n - `\'majority\'` will only return values that are safely committed on disk on a majority of replicas. This requires sending a message to every replica on each read, so it is the slowest but most consistent.\n - `\'outdated\'` will return values that are in memory on an arbitrarily-selected replica. This is the fastest but least consistent.\n- `time_format`: what format to return times in (default: `\'native\'`).\n Set this to `\'raw\'` if you want times returned as JSON objects for exporting.\n- `profile`: whether or not to return a profile of the query\'s\n execution (default: `False`).\n- `durability`: possible values are `\'hard\'` and `\'soft\'`. In soft durability mode RethinkDB\nwill acknowledge the write immediately after receiving it, but before the write has\nbeen committed to disk.\n- `group_format`: what format to return `grouped_data` and `grouped_streams` in (default: `\'native\'`).\n Set this to `\'raw\'` if you want the raw pseudotype.\n- `noreply`: set to `True` to not receive the result object or cursor and return immediately.\n- `db`: the database to run this query against as a string. The default is the database specified in the `db` parameter to [connect](http://rebirthdb.com/api/python/connect/) (which defaults to `test`). The database may also be specified with the [db](http://rebirthdb.com/api/python/db/) command.\n- `array_limit`: the maximum numbers of array elements that can be returned by a query (default: 100,000). This affects all ReQL commands that return arrays. Note that it has no effect on the size of arrays being _written_ to the database; those always have an upper limit of 100,000 elements.\n- `binary_format`: what format to return binary data in (default: `\'native\'`). Set this to `\'raw\'` if you want the raw pseudotype.\n- `min_batch_rows`: minimum number of rows to wait for before batching a result set (default: 8). This is an integer.\n- `max_batch_rows`: maximum number of rows to wait for before batching a result set (default: unlimited). This is an integer.\n- `max_batch_bytes`: maximum number of bytes to wait for before batching a result set (default: 1MB). This is an integer.\n- `max_batch_seconds`: maximum number of seconds to wait before batching a result set (default: 0.5). This is a float (not an integer) and may be specified to the microsecond.\n- `first_batch_scaledown_factor`: factor to scale the other parameters down by on the first batch (default: 4). For example, with this set to 8 and `max_batch_rows` set to 80, on the first batch `max_batch_rows` will be adjusted to 10 (80 / 8). This allows the first batch to return faster.\n\n*Example* Run a query on the connection `conn` and print out every\nrow in the result.\n\n for doc in r.table(\'marvel\').run(conn):\n print doc\n\n*Example* If you are OK with potentially out of date data from all\nthe tables involved in this query and want potentially faster reads,\npass a flag allowing out of date data in an options object. Settings\nfor individual tables will supercede this global setting for all\ntables in the query.\n\n r.table(\'marvel\').run(conn, read_mode=\'outdated\')\n\n*Example* If you just want to send a write and forget about it, you\ncan set `noreply` to true in the options. In this case `run` will\nreturn immediately.\n\n r.table(\'marvel\').run(conn, noreply=True)\n\n*Example* If you want to specify whether to wait for a write to be\nwritten to disk (overriding the table\'s default settings), you can set\n`durability` to `\'hard\'` or `\'soft\'` in the options.\n\n r.table(\'marvel\')\n .insert({ \'superhero\': \'Iron Man\', \'superpower\': \'Arc Reactor\' })\n .run(conn, noreply=True, durability=\'soft\')\n\n*Example* If you do not want a time object to be converted to a\nnative date object, you can pass a `time_format` flag to prevent it\n(valid flags are "raw" and "native"). This query returns an object\nwith two fields (`epoch_time` and `$reql_type$`) instead of a native date\nobject.\n\n r.now().run(conn, time_format="raw")\n\n*Example* Specify the database to use for the query.\n\n for doc in r.table(\'marvel\').run(conn, db=\'heroes\'):\n print doc\n\nThis is equivalent to using the `db` command to specify the database:\n\n r.db(\'heroes\').table(\'marvel\').run(conn) ...\n\n*Example* Change the batching parameters for this query.\n\n r.table(\'marvel\').run(conn, max_batch_rows=16, max_batch_bytes=2048)\n'), - (rebirthdb.net.Connection.server, b'conn.server()\n\nReturn information about the server being used by a connection.\n\nThe `server` command returns either two or three fields:\n\n* `id`: the UUID of the server the client is connected to.\n* `proxy`: a boolean indicating whether the server is a RethinkDB proxy node.\n* `name`: the server name. If `proxy` is `True`, this field will not be returned.\n\n*Example* Return server information.\n\n > conn.server()\n \n {\n "id": "404bef53-4b2c-433f-9184-bc3f7bda4a15",\n "name": "amadeus",\n "proxy": False\n }\n'), - (rebirthdb.set_loop_type, b'r.set_loop_type(string)\n\nSet an asynchronous event loop model. There are two supported models:\n\n* `"tornado"`: use the Tornado web framework. Under this model, the connect and run commands will return Tornado `Future` objects.\n* `"twisted"`: use the Twisted networking engine. Under this model, the connect and run commands will return Twisted `Deferred` objects.\n\n*Example* Read a table\'s data using Tornado.\n\n r.set_loop_type("tornado")\n conn = r.connect(host=\'localhost\', port=28015)\n \n @gen.coroutine\n def use_cursor(conn):\n # Print every row in the table.\n cursor = yield r.table(\'test\').order_by(index="id").run(yield conn)\n while (yield cursor.fetch_next()):\n item = yield cursor.next()\n print(item)\n\nFor a longer discussion with both Tornado and Twisted examples, see the documentation article on Asynchronous connections.\n\n'), - (rebirthdb.net.Connection.use, b"conn.use(db_name)\n\nChange the default database on this connection.\n\n*Example* Change the default database so that we don't need to\nspecify the database when referencing a table.\n\n conn.use('marvel')\n r.table('heroes').run(conn) # refers to r.db('marvel').table('heroes')\n"), - (rebirthdb.ast.Table.config, b'table.config() -> selection<object>\ndatabase.config() -> selection<object>\n\nQuery (read and/or update) the configurations for individual tables or databases.\n\nThe `config` command is a shorthand way to access the `table_config` or `db_config` [System tables](http://rebirthdb.com/docs/system-tables/#configuration-tables). It will return the single row from the system that corresponds to the database or table configuration, as if [get](http://rebirthdb.com/api/python/get) had been called on the system table with the UUID of the database or table in question.\n\n*Example* Get the configuration for the `users` table.\n\n r.table(\'users\').config().run(conn)\n\n\n\nExample return:\n\n \n {\n "id": "31c92680-f70c-4a4b-a49e-b238eb12c023",\n "name": "users",\n "db": "superstuff",\n "primary_key": "id",\n "shards": [\n {\n "primary_replica": "a",\n "replicas": ["a", "b"],\n "nonvoting_replicas": []\n },\n {\n "primary_replica": "d",\n "replicas": ["c", "d"],\n "nonvoting_replicas": []\n }\n ],\n "indexes": [],\n "write_acks": "majority",\n "durability": "hard"\n }\n\n*Example* Change the write acknowledgement requirement of the `users` table.\n\n r.table(\'users\').config().update({\'write_acks\': \'single\'}).run(conn)\n'), - (rebirthdb.grant, b'r.grant("username", {"permission": bool[, ...]}) -> object\ndb.grant("username", {"permission": bool[, ...]}) -> object\ntable.grant("username", {"permission": bool[, ...]}) -> object\n\nGrant or deny access permissions for a user account, globally or on a per-database or per-table basis.\n\nThere are four different permissions that can be granted to an account:\n\n* `read` allows reading the data in tables.\n* `write` allows modifying data, including inserting, replacing/updating, and deleting.\n* `connect` allows a user to open HTTP connections via the http command. This permission can only be granted in global scope.\n* `config` allows users to create/drop secondary indexes on a table and changing the cluster configuration; to create and drop tables, if granted on a database; and to create and drop databases, if granted globally.\n\nPermissions may be granted on a global scope, or granted for a specific table or database. The scope is defined by calling `grant` on its own (e.g., `r.grant()`, on a table (`r.table().grant()`), or on a database (`r.db().grant()`).\n\nThe `grant` command returns an object of the following form:\n\n {\n "granted": 1,\n "permissions_changes": [\n {\n "new_val": { new permissions },\n "old_val": { original permissions }\n }\n ]\n\nThe `granted` field will always be `1`, and the `permissions_changes` list will have one object, describing the new permissions values and the old values they were changed from (which may be `None`).\n\nPermissions that are not defined on a local scope will be inherited from the next largest scope. For example, a write operation on a table will first check if `write` permissions are explicitly set to `True` or `False` for that table and account combination; if they are not, the `write` permissions for the database will be used if those are explicitly set; and if neither table nor database permissions are set for that account, the global `write` permissions for that account will be used.\n\n__Note:__ For all accounts other than the special, system-defined `admin` account, permissions that are not explicitly set in any scope will effectively be `False`. When you create a new user account by inserting a record into the system table, that account will have _no_ permissions until they are explicitly granted.\n\nFor a full description of permissions, read Permissions and user accounts.\n\n*Example* Grant the `chatapp` user account read and write permissions on the `users` database.\n\n > r.db(\'users\').grant(\'chatapp\', {\'read\': True, \'write\': True}).run(conn)\n \n {\n "granted": 1,\n "permissions_changes": [\n {\n "new_val": { "read": true, "write": true },\n "old_val": { null }\n }\n ]\n\n*Example* Deny write permissions from the `chatapp` account for the `admin` table.\n\n r.db(\'users\').table(\'admin\').grant(\'chatapp\', {\'write\': False}).run(conn)\n\nThis will override the `write: true` permissions granted in the first example, but for this table only. Other tables in the `users` database will inherit from the database permissions.\n\n*Example* Delete a table-level permission for the `chatapp` account.\n\n r.db(\'users\').table(\'admin\').grant(\'chatapp\', {\'write\': None}).run(conn)\n\nBy specifying `None`, the table scope `write` permission is removed, and will again inherit from the next highest scope (database or global).\n\n*Example* Grant `chatapp` the ability to use HTTP connections.\n\n r.grant(\'chatapp\', {\'connect\': True}).run(conn)\n\nThis grant can only be given on a global level.\n\n*Example* Grant a `monitor` account read-only access to all databases.\n\n r.grant(\'monitor\', {\'read\': True}).run(conn)\n'), - (rebirthdb.ast.Table.rebalance, b'table.rebalance() -> object\ndatabase.rebalance() -> object\n\nRebalances the shards of a table. When called on a database, all the tables in that database will be rebalanced.\n\nThe `rebalance` command operates by measuring the distribution of primary keys within a table and picking split points that will give each shard approximately the same number of documents. It won\'t change the number of shards within a table, or change any other configuration aspect for the table or the database.\n\nA table will lose availability temporarily after `rebalance` is called; use the [wait](http://rebirthdb.com/api/python/wait) command to wait for the table to become available again, or [status](http://rebirthdb.com/api/python/status) to check if the table is available for writing.\n\nRethinkDB automatically rebalances tables when the number of shards are increased, and as long as your documents have evenly distributed primary keys—such as the default UUIDs—it is rarely necessary to call `rebalance` manually. Cases where `rebalance` may need to be called include:\n\n* Tables with unevenly distributed primary keys, such as incrementing integers\n* Changing a table\'s primary key type\n* Increasing the number of shards on an empty table, then using non-UUID primary keys in that table\n\nThe [web UI](http://rebirthdb.com/docs/administration-tools/) (and the [info](http://rebirthdb.com/api/python/info) command) can be used to tell you when a table\'s shards need to be rebalanced.\n\nThe return value of `rebalance` is an object with two fields:\n\n* `rebalanced`: the number of tables rebalanced.\n* `status_changes`: a list of new and old table status values. Each element of the list will be an object with two fields:\n * `old_val`: The table\'s [status](http://rebirthdb.com/api/python/status) value before `rebalance` was executed. \n * `new_val`: The table\'s `status` value after `rebalance` was executed. (This value will almost always indicate the table is unavailable.)\n\nSee the [status](http://rebirthdb.com/api/python/status) command for an explanation of the objects returned in the `old_val` and `new_val` fields.\n\n*Example* Rebalance a table.\n\n r.table(\'superheroes\').rebalance().run(conn)\n\n\n\nExample return:\n\n {\n "rebalanced": 1,\n "status_changes": [\n {\n "old_val": {\n "db": "database",\n "id": "5cb35225-81b2-4cec-9eef-bfad15481265",\n "name": "superheroes",\n "shards": [\n {\n "primary_replica": "jeeves",\n "replicas": [\n {\n "server": "jeeves",\n "state": "ready"\n }\n ]\n },\n {\n "primary_replica": "jeeves",\n "replicas": [\n {\n "server": "jeeves",\n "state": "ready"\n }\n ]\n }\n ],\n "status": {\n "all_replicas_ready": True,\n "ready_for_outdated_reads": True,\n "ready_for_reads": True,\n "ready_for_writes": True\n }\n },\n "new_val": {\n "db": "database",\n "id": "5cb35225-81b2-4cec-9eef-bfad15481265",\n "name": "superheroes",\n "shards": [\n {\n "primary_replica": "jeeves",\n "replicas": [\n {\n "server": "jeeves",\n "state": "transitioning"\n }\n ]\n },\n {\n "primary_replica": "jeeves",\n "replicas": [\n {\n "server": "jeeves",\n "state": "transitioning"\n }\n ]\n }\n ],\n "status": {\n "all_replicas_ready": False,\n "ready_for_outdated_reads": False,\n "ready_for_reads": False,\n "ready_for_writes": False\n }\n }\n \n }\n ]\n }\n'), - (rebirthdb.ast.Table.reconfigure, b'table.reconfigure(shards=, replicas=[, primary_replica_tag=, dry_run=False, nonvoting_replica_tags=None]) -> object\ndatabase.reconfigure(shards=, replicas=[, primary_replica_tag=, dry_run=False, nonvoting_replica_tags=None]) -> object\ntable.reconfigure(emergency_repair=