From b63cd380211ee91f47ff59bae865a4eff1c069dc Mon Sep 17 00:00:00 2001 From: Frost Ming Date: Mon, 8 Jan 2024 18:15:17 +0800 Subject: [PATCH] feat: modernize with PDM (#304) * feat: modernize with PDM Signed-off-by: Frost Ming * doc: update README Signed-off-by: Frost Ming * run under pdm env Signed-off-by: Frost Ming * requires-python `>=3.7` * fix: update lockfile Signed-off-by: Frost Ming * fix: separate example tests Signed-off-by: Frost Ming * fix lint Signed-off-by: Frost Ming * fix: try fixing by upgrading coverage Signed-off-by: Frost Ming --------- Signed-off-by: Frost Ming Co-authored-by: Wey Gu --- .github/workflows/deploy_release.yaml | 31 +- .github/workflows/run_test.yaml | 57 +- .gitignore | 1 + Makefile | 25 - README.md | 61 ++- example/FormatResp.py | 1 + example/GraphClientMultiThreadExample.py | 60 +-- example/GraphClientSimpleExample.py | 22 +- example/ScanVertexEdgeExample.py | 43 +- example/SessinPoolExample.py | 25 +- pdm.lock | 644 +++++++++++++++++++++++ pyproject.toml | 61 +++ requirements/dev.in | 3 - requirements/dev.txt | 58 -- requirements/example.in | 2 - requirements/example.txt | 20 - requirements/test.in | 2 - requirements/test.txt | 22 - setup.py | 34 -- tests/test_connection.py | 24 +- tests/test_data_from_server.py | 121 ++--- tests/test_data_type.py | 209 ++++---- tests/test_graph_storage_client.py | 136 +++-- tests/test_meta_cache.py | 88 ++-- tests/test_pool.py | 109 ++-- tests/test_session.py | 49 +- tests/test_session_pool.py | 82 ++- tests/test_ssl_connection.py | 54 +- tests/test_ssl_pool.py | 29 +- 29 files changed, 1281 insertions(+), 792 deletions(-) delete mode 100644 Makefile create mode 100644 pdm.lock create mode 100644 pyproject.toml delete mode 100644 requirements/dev.in delete mode 100644 requirements/dev.txt delete mode 100644 requirements/example.in delete mode 100644 requirements/example.txt delete mode 100644 requirements/test.in delete mode 100644 requirements/test.txt delete mode 100644 setup.py diff --git a/.github/workflows/deploy_release.yaml b/.github/workflows/deploy_release.yaml index b09b6fe0..88ce210e 100644 --- a/.github/workflows/deploy_release.yaml +++ b/.github/workflows/deploy_release.yaml @@ -10,31 +10,26 @@ jobs: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v3 + - uses: pdm-project/setup-pdm@v3 + with: + python-version: '3.x' + cache: true - name: Install dependencies - run: | - python3 -m pip install --upgrade pip - pip3 install setuptools wheel twine - pip install . - pip install -r requirements/dev.txt + run: pdm install - name: Test with pytest run: | - docker-compose -f docker-compose.yaml up -d + docker-compose -f tests/docker-compose.yaml up -d sleep 20 - pytest -s -v -k "not SSL" - working-directory: tests + pdm test - name: Test SSL connection with pytest run: | - enable_ssl=true docker-compose -f docker-compose-ssl.yaml up -d + enable_ssl=true docker-compose -f tests/docker-compose-ssl.yaml up -d sleep 20 - pytest -s -v -k "SSL" - working-directory: tests + pdm test-ssl - name: Build and publish env: - TWINE_USERNAME: ${{ secrets.PYPI_NAME }} - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} - run: | - python3 setup.py sdist bdist_wheel - twine upload dist/* + PDM_PUBLISH_USERNAME: ${{ secrets.PYPI_NAME }} + PDM_PUBLISH_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: pdm publish diff --git a/.github/workflows/run_test.yaml b/.github/workflows/run_test.yaml index ce790c10..37628519 100644 --- a/.github/workflows/run_test.yaml +++ b/.github/workflows/run_test.yaml @@ -10,11 +10,11 @@ on: jobs: ci: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: max-parallel: 2 matrix: - python-version: [3.9, '3.10', 3.11, 3.12] + python-version: [3.7, 3.8, 3.9, '3.10', 3.11, 3.12] steps: - name: Maximize runner space @@ -27,35 +27,48 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: pdm-project/setup-pdm@v3 with: python-version: ${{ matrix.python-version }} - - name: lint - run: make fmt-check + cache: true + - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install . - pip install -r requirements/dev.txt + run: pdm install + - name: lint + run: pdm fmt-check - name: Test with pytest run: | - docker-compose -f docker-compose.yaml up -d + docker-compose -f tests/docker-compose.yaml up -d sleep 20 - pytest -s -v -k "not SSL" --cov=../nebula3 --cov-report=xml --cov-append - working-directory: tests + pdm test - name: Test SSL connection with pytest run: | - enable_ssl=true docker-compose -f docker-compose-ssl.yaml up -d - sleep 20 - pytest -s -v -k "SSL" --cov=../nebula3 --cov-report=xml --cov-append - working-directory: tests - - name: Test example - run: | - docker-compose -f ../tests/docker-compose.yaml up -d + enable_ssl=true docker-compose -f tests/docker-compose-ssl.yaml up -d sleep 20 - for f in *.py; do python "$f"; done - working-directory: example + pdm test-ssl - name: Upload Coverage to Codecov uses: codecov/codecov-action@v3 with: - files: ./tests/coverage.xml + files: coverage.xml + + example: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.11, 3.12] + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: pdm-project/setup-pdm@v3 + with: + python-version: ${{ matrix.python-version }} + cache: true + - name: Install dependencies + run: pdm install -G example + - name: Setup containers + run: | + docker-compose -f tests/docker-compose.yaml up -d + sleep 20 + - name: Test example + run: | + for f in example/*.py; do pdm run python "$f"; done diff --git a/.gitignore b/.gitignore index 4e8c3805..875ffc8f 100644 --- a/.gitignore +++ b/.gitignore @@ -115,3 +115,4 @@ nebula/graph.thrift # CI data tests/data tests/logs +.pdm-python diff --git a/Makefile b/Makefile deleted file mode 100644 index ad68249c..00000000 --- a/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2021 vesoft inc. All rights reserved. -# -# This source code is licensed under Apache 2.0 License. - -.PHONY: fmt - -LINUX_BLACK = ~/.local/bin/black -MAC_BLACK = black -FMT_EXCLUDE = --extend-exclude nebula3/common/\|nebula3/storage/\|nebula3/graph/\|nebula3/meta\|nebula3/common\|nebula3/fbthrift/\|docs/source/ - -fmt: - pip install --user black==22.8.0 - @if [ -x $(LINUX_BLACK) ];then \ - $(LINUX_BLACK) -S $(FMT_EXCLUDE) .; \ - else \ - $(MAC_BLACK) -S $(FMT_EXCLUDE) .; \ - fi - -fmt-check: - pip install --user black==22.8.0 - @if [ -x $(LINUX_BLACK) ];then \ - $(LINUX_BLACK) -S --check $(FMT_EXCLUDE) .; \ - else \ - $(MAC_BLACK) -S --check $(FMT_EXCLUDE) . ; \ - fi diff --git a/README.md b/README.md index 30b60023..23258437 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ This repository holds the official Python API for NebulaGraph. +[![pdm-managed](https://img.shields.io/badge/pdm-managed-blueviolet)](https://pdm.fming.dev) + ## Before you start Before you start, please read this section to choose the right branch for you. The compatibility between the API and NebulaGraph service can be found in [How to choose nebula-python](#How-to-choose-nebula-python). The current master branch is compatible with NebulaGraph 3.x. @@ -13,24 +15,24 @@ Before you start, please read this section to choose the right branch for you. T | |-- nebula3 // client code | |-- fbthrift // the fbthrift lib code - | |-- common - | |-- data - | |-- graph - | |-- meta + | |-- common + | |-- data + | |-- graph + | |-- meta | |-- net // the net code for graph client - | |-- storage + | |-- storage | |-- Config.py // the pool config | |__ Exception.py // the define exception - | + | |-- examples | |-- GraphClientMultiThreadExample.py // the multi thread example | |-- GraphClientSimpleExample.py // the simple example - | |__ ScanVertexEdgeExample.py + | |__ ScanVertexEdgeExample.py | |-- tests // the test code - | + | |-- setup.py // used to install or package - | + | |__ README.md // the introduction of nebula3-python ``` @@ -154,7 +156,7 @@ connection_pool.close() ## Quick example to use storage-client to scan vertex and edge -You should make sure the scan client can connect to the address of storage which see from `SHOW HOSTS` +You should make sure the scan client can connect to the address of storage which see from `SHOW HOSTS` ```python from nebula3.mclient import MetaCache, HostAddr @@ -182,7 +184,7 @@ while resp.has_next(): result = resp.next() for vertex_data in result: print(vertex_data) - + resp = graph_storage_client.scan_edge( space_name='ScanSpace', edge_name='friend') @@ -195,16 +197,16 @@ while resp.has_next(): ## How to choose nebula-python | Nebula-Python Version | NebulaGraph Version | -|---|---| -| 1.0 | 1.x | -| 2.0.0 | 2.0.0/2.0.1 | -| 2.5.0 | 2.5.0 | -| 2.6.0 | 2.6.0/2.6.1 | -| 3.0.0 | 3.0.0 | -| 3.1.0 | 3.1.0 | -| 3.3.0 | 3.3.0 | -| 3.4.0 | >=3.4.0 | -| master | master | +| --------------------- | ------------------- | +| 1.0 | 1.x | +| 2.0.0 | 2.0.0/2.0.1 | +| 2.5.0 | 2.5.0 | +| 2.6.0 | 2.6.0/2.6.1 | +| 3.0.0 | 3.0.0 | +| 3.1.0 | 3.1.0 | +| 3.3.0 | 3.3.0 | +| 3.4.0 | >=3.4.0 | +| master | master | ## How to contribute to nebula-python @@ -215,18 +217,25 @@ git clone https://github.com/{username}/nebula-python.git cd nebula-python ``` -Install the package in the editable mode, then install all the dev dependencies: +We use [PMD](https://github.com/pdm-project/pdm) to manage the package, install it first: + +``` +pipx install pdm +``` + +Visit the [PDM documentation](https://pdm-project.org) for alternative installation methods. + +Install the package and all dev dependencies: ``` -pip install -e . -pip install -r requirements/dev.txt +pdm install ``` Make sure the Nebula server in running, then run the tests with pytest: ``` -pytest +pdm test ``` Using the default formatter with [black](https://github.com/psf/black). -Please run `make fmt` to format python code before submitting. +Please run `pdm fmt` to format python code before submitting. See [How to contribute](https://github.com/vesoft-inc/nebula-community/blob/master/Contributors/how-to-contribute.md) for the general process of contributing to Nebula projects. diff --git a/example/FormatResp.py b/example/FormatResp.py index 52a16500..1ce40835 100644 --- a/example/FormatResp.py +++ b/example/FormatResp.py @@ -10,6 +10,7 @@ import pandas as pd import prettytable + from nebula3.data.DataObject import Value, ValueWrapper from nebula3.data.ResultSet import ResultSet diff --git a/example/GraphClientMultiThreadExample.py b/example/GraphClientMultiThreadExample.py index 1abfb6a0..6bb94a6d 100644 --- a/example/GraphClientMultiThreadExample.py +++ b/example/GraphClientMultiThreadExample.py @@ -6,36 +6,32 @@ # This source code is licensed under Apache 2.0 License. -import sys -import time import threading +import time +from FormatResp import print_resp -sys.path.insert(0, '../') - - -from nebula3.gclient.net import ConnectionPool from nebula3.Config import Config -from FormatResp import print_resp +from nebula3.gclient.net import ConnectionPool def main_test(): client = None try: - space_name = 'space_' + threading.current_thread().name + space_name = "space_" + threading.current_thread().name print( - 'thread name: %s, space_name : %s' + "thread name: %s, space_name : %s" % (threading.current_thread().name, space_name) ) # Get one gclient - client = connection_pool.get_session('root', 'nebula') + client = connection_pool.get_session("root", "nebula") assert client is not None # Create space mySpace and schema resp = client.execute( - 'CREATE SPACE IF NOT EXISTS {} (vid_type=FIXED_STRING(30)); USE {};' - 'CREATE TAG IF NOT EXISTS person(name string, age int);' - 'CREATE EDGE IF NOT EXISTS like(likeness double);'.format( + "CREATE SPACE IF NOT EXISTS {} (vid_type=FIXED_STRING(30)); USE {};" + "CREATE TAG IF NOT EXISTS person(name string, age int);" + "CREATE EDGE IF NOT EXISTS like(likeness double);".format( space_name, space_name ) ) @@ -45,38 +41,38 @@ def main_test(): # Insert vertexes client.execute( - 'INSERT VERTEX person(name, age) VALUES ' - '\'Bob\':(\'Bob\', 10), ' - '\'Lily\':(\'Lily\', 9), ' - '\'Tom\':(\'Tom\', 10), ' - '\'Jerry\':(\'Jerry\', 13), ' - '\'John\':(\'John\', 11)' + "INSERT VERTEX person(name, age) VALUES " + "'Bob':('Bob', 10), " + "'Lily':('Lily', 9), " + "'Tom':('Tom', 10), " + "'Jerry':('Jerry', 13), " + "'John':('John', 11)" ) assert resp.is_succeeded(), resp.error_msg() # Insert edges client.execute( - 'INSERT EDGE like(likeness) VALUES ' - '\'Bob\'->\'Lily\':(80.0), ' - '\'Bob\'->\'Tom\':(70.0), ' - '\'Lily\'->\'Jerry\':(84.0), ' - '\'Tom\'->\'Jerry\':(68.3), ' - '\'Bob\'->\'John\':(97.2)' + "INSERT EDGE like(likeness) VALUES " + "'Bob'->'Lily':(80.0), " + "'Bob'->'Tom':(70.0), " + "'Lily'->'Jerry':(84.0), " + "'Tom'->'Jerry':(68.3), " + "'Bob'->'John':(97.2)" ) # Query data query_resp = client.execute( - 'GO FROM \"Bob\" OVER like YIELD $^.person.name, ' - '$^.person.age, like.likeness' + 'GO FROM "Bob" OVER like YIELD $^.person.name, ' + "$^.person.age, like.likeness" ) if not query_resp.is_succeeded(): - print('Execute failed: %s' % query_resp.error_msg()) + print("Execute failed: %s" % query_resp.error_msg()) exit(1) # Print the result of query print( - ' \n====== The query result of thread[%s]======\n ' + " \n====== The query result of thread[%s]======\n " % threading.current_thread().name ) print_resp(query_resp) @@ -91,20 +87,20 @@ def main_test(): client.release() -if __name__ == '__main__': +if __name__ == "__main__": config = Config() config.max_connection_pool_size = 4 # init connection pool connection_pool = ConnectionPool() - assert connection_pool.init([('127.0.0.1', 9669), ('127.0.0.1', 9670)], config) + assert connection_pool.init([("127.0.0.1", 9669), ("127.0.0.1", 9670)], config) # Use multi thread and reuse the session three times for count in range(0, 3): threads = list() for i in range(0, 4): threads.append( - threading.Thread(target=main_test, name='thread{}'.format(i)) + threading.Thread(target=main_test, name="thread{}".format(i)) ) for thread in threads: diff --git a/example/GraphClientSimpleExample.py b/example/GraphClientSimpleExample.py index b0cc9727..5e7457c4 100644 --- a/example/GraphClientSimpleExample.py +++ b/example/GraphClientSimpleExample.py @@ -6,25 +6,25 @@ # This source code is licensed under Apache 2.0 License. -import time import json +import time -from nebula3.gclient.net import ConnectionPool +from FormatResp import print_resp from nebula3.Config import Config -from FormatResp import print_resp +from nebula3.gclient.net import ConnectionPool -if __name__ == '__main__': +if __name__ == "__main__": client = None try: config = Config() config.max_connection_pool_size = 2 # init connection pool connection_pool = ConnectionPool() - assert connection_pool.init([('127.0.0.1', 9669)], config) + assert connection_pool.init([("127.0.0.1", 9669)], config) # get session from the pool - client = connection_pool.get_session('root', 'nebula') + client = connection_pool.get_session("root", "nebula") assert client is not None # get the result in json format @@ -33,9 +33,9 @@ print(json.dumps(json_obj, indent=2, sort_keys=True)) client.execute( - 'CREATE SPACE IF NOT EXISTS test(vid_type=FIXED_STRING(30)); USE test;' - 'CREATE TAG IF NOT EXISTS person(name string, age int);' - 'CREATE EDGE like (likeness double);' + "CREATE SPACE IF NOT EXISTS test(vid_type=FIXED_STRING(30)); USE test;" + "CREATE TAG IF NOT EXISTS person(name string, age int);" + "CREATE EDGE like (likeness double);" ) # insert data need to sleep after create schema @@ -60,12 +60,12 @@ print_resp(resp) # drop space - resp = client.execute('DROP SPACE test') + resp = client.execute("DROP SPACE test") assert resp.is_succeeded(), resp.error_msg() print("Example finished") - except Exception as x: + except Exception: import traceback print(traceback.format_exc()) diff --git a/example/ScanVertexEdgeExample.py b/example/ScanVertexEdgeExample.py index 7efc893d..2366169c 100644 --- a/example/ScanVertexEdgeExample.py +++ b/example/ScanVertexEdgeExample.py @@ -7,11 +7,8 @@ import random -import sys import time -sys.path.insert(0, '../') - from nebula3.Config import Config from nebula3.gclient.net import ConnectionPool from nebula3.mclient import MetaCache @@ -24,30 +21,30 @@ def prepare_data(): # init connection pool connection_pool = ConnectionPool() # the graphd server's address - assert connection_pool.init([('127.0.0.1', 9671)], config) - client = connection_pool.get_session('root', 'nebula') + assert connection_pool.init([("127.0.0.1", 9671)], config) + client = connection_pool.get_session("root", "nebula") client.execute( - 'CREATE SPACE IF NOT EXISTS ScanSpace(' - 'PARTITION_NUM=10,' - 'vid_type=FIXED_STRING(20));' - 'USE ScanSpace;' - 'CREATE TAG IF NOT EXISTS person(name string, age int);' - 'CREATE EDGE IF NOT EXISTS friend(start int, end int);' + "CREATE SPACE IF NOT EXISTS ScanSpace(" + "PARTITION_NUM=10," + "vid_type=FIXED_STRING(20));" + "USE ScanSpace;" + "CREATE TAG IF NOT EXISTS person(name string, age int);" + "CREATE EDGE IF NOT EXISTS friend(start int, end int);" ) time.sleep(5) for id in range(20): - vid = 'person' + str(id) - cmd = 'INSERT VERTEX person(name, age) ' 'VALUES \"{}\":(\"{}\", {})'.format( + vid = "person" + str(id) + cmd = "INSERT VERTEX person(name, age) " 'VALUES "{}":("{}", {})'.format( vid, vid, id ) client.execute(cmd) for id in range(20): - src_id = 'person' + str(id) - dst_id = 'person' + str(20 - id) + src_id = "person" + str(id) + dst_id = "person" + str(20 - id) start = random.randint(2000, 2010) end = random.randint(2010, 2020) - cmd = 'INSERT EDGE friend(start, end) ' 'VALUES \"{}\"->\"{}\":({}, {})'.format( + cmd = "INSERT EDGE friend(start, end) " 'VALUES "{}"->"{}":({}, {})'.format( src_id, dst_id, start, end ) client.execute(cmd) @@ -57,9 +54,9 @@ def prepare_data(): def scan_person_vertex(graph_storage_client): resp = graph_storage_client.scan_vertex( - space_name='ScanSpace', tag_name='person', limit=1 + space_name="ScanSpace", tag_name="person", limit=1 ) - print('======== Scan vertexes in ScanSpace ======') + print("======== Scan vertexes in ScanSpace ======") while resp.has_next(): result = resp.next() for vertex_data in result: @@ -68,9 +65,9 @@ def scan_person_vertex(graph_storage_client): def scan_person_edge(graph_storage_client): resp = graph_storage_client.scan_edge( - space_name='ScanSpace', edge_name='friend', limit=100 + space_name="ScanSpace", edge_name="friend", limit=100 ) - print('======== Scan edges in ScanSpace ======') + print("======== Scan edges in ScanSpace ======") while resp.has_next(): result = resp.next() for edge_data in result: @@ -123,20 +120,20 @@ def scan_person_edge(graph_storage_client): (person8)-[:friend@0{'start': 2000, 'end': 2019}]->(person12) """ -if __name__ == '__main__': +if __name__ == "__main__": meta_cache = None graph_storage_client = None try: # the metad servers's address meta_cache = MetaCache( - [('172.28.1.1', 9559), ('172.28.1.2', 9559), ('172.28.1.3', 9559)], 50000 + [("172.28.1.1", 9559), ("172.28.1.2", 9559), ("172.28.1.3", 9559)], 50000 ) graph_storage_client = GraphStorageClient(meta_cache) prepare_data() scan_person_vertex(graph_storage_client) scan_person_edge(graph_storage_client) - except Exception as x: + except Exception: import traceback print(traceback.format_exc()) diff --git a/example/SessinPoolExample.py b/example/SessinPoolExample.py index f4dbf129..908af36f 100644 --- a/example/SessinPoolExample.py +++ b/example/SessinPoolExample.py @@ -7,15 +7,16 @@ import time -from nebula3.common.ttypes import ErrorCode +from FormatResp import print_resp + +from nebula3.common.ttypes import ErrorCode +from nebula3.Config import SessionPoolConfig from nebula3.gclient.net import Connection from nebula3.gclient.net.SessionPool import SessionPool -from nebula3.Config import SessionPoolConfig -from FormatResp import print_resp -if __name__ == '__main__': - ip = '127.0.0.1' +if __name__ == "__main__": + ip = "127.0.0.1" port = 9669 try: @@ -24,24 +25,24 @@ # prepare space conn = Connection() conn.open(ip, port, 1000) - auth_result = conn.authenticate('root', 'nebula') + auth_result = conn.authenticate("root", "nebula") assert auth_result.get_session_id() != 0 resp = conn.execute( auth_result._session_id, - 'CREATE SPACE IF NOT EXISTS session_pool_test(vid_type=FIXED_STRING(30))', + "CREATE SPACE IF NOT EXISTS session_pool_test(vid_type=FIXED_STRING(30))", ) assert resp.error_code == ErrorCode.SUCCEEDED # insert data need to sleep after create schema time.sleep(10) # init session pool - session_pool = SessionPool('root', 'nebula', 'session_pool_test', [(ip, port)]) + session_pool = SessionPool("root", "nebula", "session_pool_test", [(ip, port)]) assert session_pool.init(config) # add schema resp = session_pool.execute( - 'CREATE TAG IF NOT EXISTS person(name string, age int);' - 'CREATE EDGE like (likeness double);' + "CREATE TAG IF NOT EXISTS person(name string, age int);" + "CREATE EDGE like (likeness double);" ) time.sleep(6) @@ -69,12 +70,12 @@ # drop space conn.execute( auth_result._session_id, - 'DROP SPACE session_pool_test', + "DROP SPACE session_pool_test", ) print("Example finished") - except Exception as x: + except Exception: import traceback print(traceback.format_exc()) diff --git a/pdm.lock b/pdm.lock new file mode 100644 index 00000000..6c1857d3 --- /dev/null +++ b/pdm.lock @@ -0,0 +1,644 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[metadata] +groups = ["default", "dev", "test", "example"] +strategy = ["cross_platform", "inherit_metadata"] +lock_version = "4.4.1" +content_hash = "sha256:1be652ca4a8839a58ad03cf77a9ed3556f04efff11c8f56e51a9fd7d9e553bb3" + +[[package]] +name = "black" +version = "22.8.0" +requires_python = ">=3.6.2" +summary = "The uncompromising code formatter." +groups = ["dev"] +dependencies = [ + "click>=8.0.0", + "mypy-extensions>=0.4.3", + "pathspec>=0.9.0", + "platformdirs>=2", + "tomli>=1.1.0; python_full_version < \"3.11.0a7\"", + "typed-ast>=1.4.2; python_version < \"3.8\" and implementation_name == \"cpython\"", + "typing-extensions>=3.10.0.0; python_version < \"3.10\"", +] +files = [ + {file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"}, + {file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"}, + {file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"}, + {file = "black-22.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869"}, + {file = "black-22.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90"}, + {file = "black-22.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3"}, + {file = "black-22.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e"}, + {file = "black-22.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16"}, + {file = "black-22.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c"}, + {file = "black-22.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5"}, + {file = "black-22.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411"}, + {file = "black-22.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3"}, + {file = "black-22.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"}, + {file = "black-22.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c"}, + {file = "black-22.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497"}, + {file = "black-22.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c"}, + {file = "black-22.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41"}, + {file = "black-22.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec"}, + {file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"}, + {file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"}, +] + +[[package]] +name = "click" +version = "8.1.7" +requires_python = ">=3.7" +summary = "Composable command line interface toolkit" +groups = ["dev"] +dependencies = [ + "colorama; platform_system == \"Windows\"", + "importlib-metadata; python_version < \"3.8\"", +] +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." +groups = ["dev", "test"] +marker = "sys_platform == \"win32\" and python_full_version >= \"3.7.1\" or platform_system == \"Windows\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.2.7" +requires_python = ">=3.7" +summary = "Code coverage measurement for Python" +groups = ["test"] +marker = "python_full_version >= \"3.7.1\"" +files = [ + {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, + {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, + {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, + {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, + {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, + {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, + {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, + {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, + {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, + {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, + {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, + {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, + {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, + {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, + {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, + {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, + {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, + {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, +] + +[[package]] +name = "coverage" +version = "7.2.7" +extras = ["toml"] +requires_python = ">=3.7" +summary = "Code coverage measurement for Python" +groups = ["test"] +marker = "python_full_version >= \"3.7.1\"" +dependencies = [ + "coverage==7.2.7", + "tomli; python_full_version <= \"3.11.0a6\"", +] +files = [ + {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, + {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, + {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, + {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, + {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, + {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, + {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, + {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, + {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, + {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, + {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, + {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, + {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, + {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, + {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, + {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, + {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, + {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +requires_python = ">=3.7" +summary = "Backport of PEP 654 (exception groups)" +groups = ["test"] +marker = "python_version < \"3.11\" and python_full_version >= \"3.7.1\"" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[[package]] +name = "future" +version = "0.18.3" +requires_python = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +summary = "Clean single-source support for Python 3 and 2" +groups = ["default"] +files = [ + {file = "future-0.18.3.tar.gz", hash = "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307"}, +] + +[[package]] +name = "httplib2" +version = "0.22.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +summary = "A comprehensive HTTP client library." +groups = ["default"] +dependencies = [ + "pyparsing!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3,<4,>=2.4.2; python_version > \"3.0\"", +] +files = [ + {file = "httplib2-0.22.0-py3-none-any.whl", hash = "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc"}, + {file = "httplib2-0.22.0.tar.gz", hash = "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81"}, +] + +[[package]] +name = "importlib-metadata" +version = "6.7.0" +requires_python = ">=3.7" +summary = "Read metadata from Python packages" +groups = ["dev", "test"] +marker = "python_version < \"3.8\"" +dependencies = [ + "typing-extensions>=3.6.4; python_version < \"3.8\"", + "zipp>=0.5", +] +files = [ + {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, + {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +requires_python = ">=3.7" +summary = "brain-dead simple config-ini parsing" +groups = ["test"] +marker = "python_full_version >= \"3.7.1\"" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +requires_python = ">=3.5" +summary = "Type system extensions for programs checked with the mypy type checker." +groups = ["dev"] +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "numpy" +version = "1.26.3" +requires_python = ">=3.9" +summary = "Fundamental package for array computing in Python" +groups = ["example"] +marker = "python_version <= \"3.11\" and python_version >= \"3.10\" or python_version >= \"3.12\"" +files = [ + {file = "numpy-1.26.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:806dd64230dbbfaca8a27faa64e2f414bf1c6622ab78cc4264f7f5f028fee3bf"}, + {file = "numpy-1.26.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f98011ba4ab17f46f80f7f8f1c291ee7d855fcef0a5a98db80767a468c85cd"}, + {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d45b3ec2faed4baca41c76617fcdcfa4f684ff7a151ce6fc78ad3b6e85af0a6"}, + {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdd2b45bf079d9ad90377048e2747a0c82351989a2165821f0c96831b4a2a54b"}, + {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:211ddd1e94817ed2d175b60b6374120244a4dd2287f4ece45d49228b4d529178"}, + {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1240f767f69d7c4c8a29adde2310b871153df9b26b5cb2b54a561ac85146485"}, + {file = "numpy-1.26.3-cp310-cp310-win32.whl", hash = "sha256:21a9484e75ad018974a2fdaa216524d64ed4212e418e0a551a2d83403b0531d3"}, + {file = "numpy-1.26.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e1591f6ae98bcfac2a4bbf9221c0b92ab49762228f38287f6eeb5f3f55905ce"}, + {file = "numpy-1.26.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b831295e5472954104ecb46cd98c08b98b49c69fdb7040483aff799a755a7374"}, + {file = "numpy-1.26.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e87562b91f68dd8b1c39149d0323b42e0082db7ddb8e934ab4c292094d575d6"}, + {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c66d6fec467e8c0f975818c1796d25c53521124b7cfb760114be0abad53a0a2"}, + {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f25e2811a9c932e43943a2615e65fc487a0b6b49218899e62e426e7f0a57eeda"}, + {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:af36e0aa45e25c9f57bf684b1175e59ea05d9a7d3e8e87b7ae1a1da246f2767e"}, + {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:51c7f1b344f302067b02e0f5b5d2daa9ed4a721cf49f070280ac202738ea7f00"}, + {file = "numpy-1.26.3-cp311-cp311-win32.whl", hash = "sha256:7ca4f24341df071877849eb2034948459ce3a07915c2734f1abb4018d9c49d7b"}, + {file = "numpy-1.26.3-cp311-cp311-win_amd64.whl", hash = "sha256:39763aee6dfdd4878032361b30b2b12593fb445ddb66bbac802e2113eb8a6ac4"}, + {file = "numpy-1.26.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a7081fd19a6d573e1a05e600c82a1c421011db7935ed0d5c483e9dd96b99cf13"}, + {file = "numpy-1.26.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12c70ac274b32bc00c7f61b515126c9205323703abb99cd41836e8125ea0043e"}, + {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f784e13e598e9594750b2ef6729bcd5a47f6cfe4a12cca13def35e06d8163e3"}, + {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f24750ef94d56ce6e33e4019a8a4d68cfdb1ef661a52cdaee628a56d2437419"}, + {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:77810ef29e0fb1d289d225cabb9ee6cf4d11978a00bb99f7f8ec2132a84e0166"}, + {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8ed07a90f5450d99dad60d3799f9c03c6566709bd53b497eb9ccad9a55867f36"}, + {file = "numpy-1.26.3-cp312-cp312-win32.whl", hash = "sha256:f73497e8c38295aaa4741bdfa4fda1a5aedda5473074369eca10626835445511"}, + {file = "numpy-1.26.3-cp312-cp312-win_amd64.whl", hash = "sha256:da4b0c6c699a0ad73c810736303f7fbae483bcb012e38d7eb06a5e3b432c981b"}, + {file = "numpy-1.26.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1666f634cb3c80ccbd77ec97bc17337718f56d6658acf5d3b906ca03e90ce87f"}, + {file = "numpy-1.26.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18c3319a7d39b2c6a9e3bb75aab2304ab79a811ac0168a671a62e6346c29b03f"}, + {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b7e807d6888da0db6e7e75838444d62495e2b588b99e90dd80c3459594e857b"}, + {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4d362e17bcb0011738c2d83e0a65ea8ce627057b2fdda37678f4374a382a137"}, + {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b8c275f0ae90069496068c714387b4a0eba5d531aace269559ff2b43655edd58"}, + {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cc0743f0302b94f397a4a65a660d4cd24267439eb16493fb3caad2e4389bccbb"}, + {file = "numpy-1.26.3-cp39-cp39-win32.whl", hash = "sha256:9bc6d1a7f8cedd519c4b7b1156d98e051b726bf160715b769106661d567b3f03"}, + {file = "numpy-1.26.3-cp39-cp39-win_amd64.whl", hash = "sha256:867e3644e208c8922a3be26fc6bbf112a035f50f0a86497f98f228c50c607bb2"}, + {file = "numpy-1.26.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3c67423b3703f8fbd90f5adaa37f85b5794d3366948efe9a5190a5f3a83fc34e"}, + {file = "numpy-1.26.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f47ee566d98849323f01b349d58f2557f02167ee301e5e28809a8c0e27a2d0"}, + {file = "numpy-1.26.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8474703bffc65ca15853d5fd4d06b18138ae90c17c8d12169968e998e448bb5"}, + {file = "numpy-1.26.3.tar.gz", hash = "sha256:697df43e2b6310ecc9d95f05d5ef20eacc09c7c4ecc9da3f235d39e71b7da1e4"}, +] + +[[package]] +name = "packaging" +version = "23.2" +requires_python = ">=3.7" +summary = "Core utilities for Python packages" +groups = ["test"] +marker = "python_full_version >= \"3.7.1\"" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pandas" +version = "2.1.4" +requires_python = ">=3.9" +summary = "Powerful data structures for data analysis, time series, and statistics" +groups = ["example"] +marker = "python_version >= \"3.10\"" +dependencies = [ + "numpy<2,>=1.22.4; python_version < \"3.11\"", + "numpy<2,>=1.23.2; python_version == \"3.11\"", + "numpy<2,>=1.26.0; python_version >= \"3.12\"", + "python-dateutil>=2.8.2", + "pytz>=2020.1", + "tzdata>=2022.1", +] +files = [ + {file = "pandas-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bdec823dc6ec53f7a6339a0e34c68b144a7a1fd28d80c260534c39c62c5bf8c9"}, + {file = "pandas-2.1.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:294d96cfaf28d688f30c918a765ea2ae2e0e71d3536754f4b6de0ea4a496d034"}, + {file = "pandas-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b728fb8deba8905b319f96447a27033969f3ea1fea09d07d296c9030ab2ed1d"}, + {file = "pandas-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00028e6737c594feac3c2df15636d73ace46b8314d236100b57ed7e4b9ebe8d9"}, + {file = "pandas-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:426dc0f1b187523c4db06f96fb5c8d1a845e259c99bda74f7de97bd8a3bb3139"}, + {file = "pandas-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:f237e6ca6421265643608813ce9793610ad09b40154a3344a088159590469e46"}, + {file = "pandas-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b7d852d16c270e4331f6f59b3e9aa23f935f5c4b0ed2d0bc77637a8890a5d092"}, + {file = "pandas-2.1.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd7d5f2f54f78164b3d7a40f33bf79a74cdee72c31affec86bfcabe7e0789821"}, + {file = "pandas-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0aa6e92e639da0d6e2017d9ccff563222f4eb31e4b2c3cf32a2a392fc3103c0d"}, + {file = "pandas-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d797591b6846b9db79e65dc2d0d48e61f7db8d10b2a9480b4e3faaddc421a171"}, + {file = "pandas-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2d3e7b00f703aea3945995ee63375c61b2e6aa5aa7871c5d622870e5e137623"}, + {file = "pandas-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:dc9bf7ade01143cddc0074aa6995edd05323974e6e40d9dbde081021ded8510e"}, + {file = "pandas-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:482d5076e1791777e1571f2e2d789e940dedd927325cc3cb6d0800c6304082f6"}, + {file = "pandas-2.1.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8a706cfe7955c4ca59af8c7a0517370eafbd98593155b48f10f9811da440248b"}, + {file = "pandas-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0513a132a15977b4a5b89aabd304647919bc2169eac4c8536afb29c07c23540"}, + {file = "pandas-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9f17f2b6fc076b2a0078862547595d66244db0f41bf79fc5f64a5c4d635bead"}, + {file = "pandas-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:45d63d2a9b1b37fa6c84a68ba2422dc9ed018bdaa668c7f47566a01188ceeec1"}, + {file = "pandas-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:f69b0c9bb174a2342818d3e2778584e18c740d56857fc5cdb944ec8bbe4082cf"}, + {file = "pandas-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3f06bda01a143020bad20f7a85dd5f4a1600112145f126bc9e3e42077c24ef34"}, + {file = "pandas-2.1.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab5796839eb1fd62a39eec2916d3e979ec3130509930fea17fe6f81e18108f6a"}, + {file = "pandas-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edbaf9e8d3a63a9276d707b4d25930a262341bca9874fcb22eff5e3da5394732"}, + {file = "pandas-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ebfd771110b50055712b3b711b51bee5d50135429364d0498e1213a7adc2be8"}, + {file = "pandas-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8ea107e0be2aba1da619cc6ba3f999b2bfc9669a83554b1904ce3dd9507f0860"}, + {file = "pandas-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:d65148b14788b3758daf57bf42725caa536575da2b64df9964c563b015230984"}, + {file = "pandas-2.1.4.tar.gz", hash = "sha256:fcb68203c833cc735321512e13861358079a96c174a61f5116a1de89c58c0ef7"}, +] + +[[package]] +name = "pathspec" +version = "0.11.2" +requires_python = ">=3.7" +summary = "Utility library for gitignore style pattern matching of file paths." +groups = ["dev"] +files = [ + {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, + {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, +] + +[[package]] +name = "platformdirs" +version = "4.0.0" +requires_python = ">=3.7" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +groups = ["dev"] +dependencies = [ + "typing-extensions>=4.7.1; python_version < \"3.8\"", +] +files = [ + {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, + {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, +] + +[[package]] +name = "pluggy" +version = "1.2.0" +requires_python = ">=3.7" +summary = "plugin and hook calling mechanisms for python" +groups = ["test"] +marker = "python_full_version >= \"3.7.1\"" +dependencies = [ + "importlib-metadata>=0.12; python_version < \"3.8\"", +] +files = [ + {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, + {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, +] + +[[package]] +name = "prettytable" +version = "3.9.0" +requires_python = ">=3.8" +summary = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" +groups = ["example"] +marker = "python_version >= \"3.10\"" +dependencies = [ + "wcwidth", +] +files = [ + {file = "prettytable-3.9.0-py3-none-any.whl", hash = "sha256:a71292ab7769a5de274b146b276ce938786f56c31cf7cea88b6f3775d82fe8c8"}, + {file = "prettytable-3.9.0.tar.gz", hash = "sha256:f4ed94803c23073a90620b201965e5dc0bccf1760b7a7eaf3158cab8aaffdf34"}, +] + +[[package]] +name = "pyparsing" +version = "3.1.1" +requires_python = ">=3.6.8" +summary = "pyparsing module - Classes and methods to define and execute parsing grammars" +groups = ["default"] +marker = "python_version > \"3.0\"" +files = [ + {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, + {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, +] + +[[package]] +name = "pytest" +version = "7.4.4" +requires_python = ">=3.7" +summary = "pytest: simple powerful testing with Python" +groups = ["test"] +marker = "python_full_version >= \"3.7.1\"" +dependencies = [ + "colorama; sys_platform == \"win32\"", + "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", + "importlib-metadata>=0.12; python_version < \"3.8\"", + "iniconfig", + "packaging", + "pluggy<2.0,>=0.12", + "tomli>=1.0.0; python_version < \"3.11\"", +] +files = [ + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, +] + +[[package]] +name = "pytest-cov" +version = "4.1.0" +requires_python = ">=3.7" +summary = "Pytest plugin for measuring coverage." +groups = ["test"] +marker = "python_full_version >= \"3.7.1\"" +dependencies = [ + "coverage[toml]>=5.2.1", + "pytest>=4.6", +] +files = [ + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, +] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +summary = "Extensions to the standard Python datetime module" +groups = ["example"] +marker = "python_version >= \"3.10\"" +dependencies = [ + "six>=1.5", +] +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[[package]] +name = "pytz" +version = "2023.3.post1" +summary = "World timezone definitions, modern and historical" +groups = ["default", "example"] +files = [ + {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, + {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, +] + +[[package]] +name = "six" +version = "1.16.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +summary = "Python 2 and 3 compatibility utilities" +groups = ["default", "example"] +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +requires_python = ">=3.7" +summary = "A lil' TOML parser" +groups = ["dev", "test"] +marker = "python_version < \"3.11\"" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "typed-ast" +version = "1.5.5" +requires_python = ">=3.6" +summary = "a fork of Python 2 and 3 ast modules with type comment support" +groups = ["dev"] +marker = "python_version < \"3.8\" and implementation_name == \"cpython\"" +files = [ + {file = "typed_ast-1.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bc1efe0ce3ffb74784e06460f01a223ac1f6ab31c6bc0376a21184bf5aabe3b"}, + {file = "typed_ast-1.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f7a8c46a8b333f71abd61d7ab9255440d4a588f34a21f126bbfc95f6049e686"}, + {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597fc66b4162f959ee6a96b978c0435bd63791e31e4f410622d19f1686d5e769"}, + {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d41b7a686ce653e06c2609075d397ebd5b969d821b9797d029fccd71fdec8e04"}, + {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5fe83a9a44c4ce67c796a1b466c270c1272e176603d5e06f6afbc101a572859d"}, + {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d5c0c112a74c0e5db2c75882a0adf3133adedcdbfd8cf7c9d6ed77365ab90a1d"}, + {file = "typed_ast-1.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:e1a976ed4cc2d71bb073e1b2a250892a6e968ff02aa14c1f40eba4f365ffec02"}, + {file = "typed_ast-1.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c631da9710271cb67b08bd3f3813b7af7f4c69c319b75475436fcab8c3d21bee"}, + {file = "typed_ast-1.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b445c2abfecab89a932b20bd8261488d574591173d07827c1eda32c457358b18"}, + {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc95ffaaab2be3b25eb938779e43f513e0e538a84dd14a5d844b8f2932593d88"}, + {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61443214d9b4c660dcf4b5307f15c12cb30bdfe9588ce6158f4a005baeb167b2"}, + {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6eb936d107e4d474940469e8ec5b380c9b329b5f08b78282d46baeebd3692dc9"}, + {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e48bf27022897577d8479eaed64701ecaf0467182448bd95759883300ca818c8"}, + {file = "typed_ast-1.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:83509f9324011c9a39faaef0922c6f720f9623afe3fe220b6d0b15638247206b"}, + {file = "typed_ast-1.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f214394fc1af23ca6d4e9e744804d890045d1643dd7e8229951e0ef39429b5"}, + {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:118c1ce46ce58fda78503eae14b7664163aa735b620b64b5b725453696f2a35c"}, + {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4919b808efa61101456e87f2d4c75b228f4e52618621c77f1ddcaae15904fa"}, + {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fc2b8c4e1bc5cd96c1a823a885e6b158f8451cf6f5530e1829390b4d27d0807f"}, + {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:16f7313e0a08c7de57f2998c85e2a69a642e97cb32f87eb65fbfe88381a5e44d"}, + {file = "typed_ast-1.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2b946ef8c04f77230489f75b4b5a4a6f24c078be4aed241cfabe9cbf4156e7e5"}, + {file = "typed_ast-1.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2188bc33d85951ea4ddad55d2b35598b2709d122c11c75cffd529fbc9965508e"}, + {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0635900d16ae133cab3b26c607586131269f88266954eb04ec31535c9a12ef1e"}, + {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57bfc3cf35a0f2fdf0a88a3044aafaec1d2f24d8ae8cd87c4f58d615fb5b6311"}, + {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fe58ef6a764de7b4b36edfc8592641f56e69b7163bba9f9c8089838ee596bfb2"}, + {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d09d930c2d1d621f717bb217bf1fe2584616febb5138d9b3e8cdd26506c3f6d4"}, + {file = "typed_ast-1.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:d40c10326893ecab8a80a53039164a224984339b2c32a6baf55ecbd5b1df6431"}, + {file = "typed_ast-1.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd946abf3c31fb50eee07451a6aedbfff912fcd13cf357363f5b4e834cc5e71a"}, + {file = "typed_ast-1.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ed4a1a42df8a3dfb6b40c3d2de109e935949f2f66b19703eafade03173f8f437"}, + {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045f9930a1550d9352464e5149710d56a2aed23a2ffe78946478f7b5416f1ede"}, + {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:381eed9c95484ceef5ced626355fdc0765ab51d8553fec08661dce654a935db4"}, + {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bfd39a41c0ef6f31684daff53befddae608f9daf6957140228a08e51f312d7e6"}, + {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8c524eb3024edcc04e288db9541fe1f438f82d281e591c548903d5b77ad1ddd4"}, + {file = "typed_ast-1.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:7f58fabdde8dcbe764cef5e1a7fcb440f2463c1bbbec1cf2a86ca7bc1f95184b"}, + {file = "typed_ast-1.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:042eb665ff6bf020dd2243307d11ed626306b82812aba21836096d229fdc6a10"}, + {file = "typed_ast-1.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:622e4a006472b05cf6ef7f9f2636edc51bda670b7bbffa18d26b255269d3d814"}, + {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1efebbbf4604ad1283e963e8915daa240cb4bf5067053cf2f0baadc4d4fb51b8"}, + {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0aefdd66f1784c58f65b502b6cf8b121544680456d1cebbd300c2c813899274"}, + {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:48074261a842acf825af1968cd912f6f21357316080ebaca5f19abbb11690c8a"}, + {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:429ae404f69dc94b9361bb62291885894b7c6fb4640d561179548c849f8492ba"}, + {file = "typed_ast-1.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:335f22ccb244da2b5c296e6f96b06ee9bed46526db0de38d2f0e5a6597b81155"}, + {file = "typed_ast-1.5.5.tar.gz", hash = "sha256:94282f7a354f36ef5dbce0ef3467ebf6a258e370ab33d5b40c249fa996e590dd"}, +] + +[[package]] +name = "typing-extensions" +version = "4.7.1" +requires_python = ">=3.7" +summary = "Backported and Experimental Type Hints for Python 3.7+" +groups = ["dev", "test"] +marker = "python_version < \"3.10\"" +files = [ + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, +] + +[[package]] +name = "tzdata" +version = "2023.4" +requires_python = ">=2" +summary = "Provider of IANA time zone data" +groups = ["example"] +marker = "python_version >= \"3.10\"" +files = [ + {file = "tzdata-2023.4-py2.py3-none-any.whl", hash = "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3"}, + {file = "tzdata-2023.4.tar.gz", hash = "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9"}, +] + +[[package]] +name = "wcwidth" +version = "0.2.12" +summary = "Measures the displayed width of unicode strings in a terminal" +groups = ["example"] +marker = "python_version >= \"3.10\"" +files = [ + {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, + {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, +] + +[[package]] +name = "zipp" +version = "3.15.0" +requires_python = ">=3.7" +summary = "Backport of pathlib-compatible object wrapper for zip files" +groups = ["dev", "test"] +marker = "python_version < \"3.8\"" +files = [ + {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, + {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..565058d5 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,61 @@ +[project] +name = "nebula3-python" +version = "3.4.0" +description = "Python client for NebulaGraph V3.4" +authors = [ + {name = "vesoft-inc", email = "info@vesoft.com"}, +] +dependencies = [ + "future >= 0.18.0", + "httplib2 >= 0.20.0", + "pytz >= 2021.1", + "six >= 1.16.0", +] +requires-python = ">=3.7" +readme = "README.md" +license = {text = "Apache 2.0"} + +[project.urls] +Homepage = "https://github.com/vesoft-inc/nebula-python" + +[build-system] +requires = ["pdm-backend"] +build-backend = "pdm.backend" + +[tool.pdm] +package-type = "library" + +[tool.pdm.build] +includes = ["nebula3"] + +[tool.pdm.dev-dependencies] +dev = [ + "black==22.8.0", +] +test = [ + "pytest; python_full_version >= \"3.7.1\"", + "pytest-cov; python_full_version >= \"3.7.1\"", +] +example = [ + "prettytable; python_version >= \"3.10\"", + "pandas; python_version >= \"3.10\"", +] + +[tool.pdm.scripts] +fmt = "black -S ." +fmt-check = "black -S --check ." +test = 'pytest -s -v -k "not SSL" --cov=nebula3/ --cov-report=xml --cov-append' +test-ssl = 'pytest -s -v -k "SSL" --cov=nebula3/ --cov-report=xml --cov-append' + +[tool.black] +extend-exclude = ''' +/( + nebula3/common + | nebula3/storage + | nebula3/graph + | nebula3/meta + | nebula3/common + | nebula3/fbthrift + | docs/source +)/ +''' diff --git a/requirements/dev.in b/requirements/dev.in deleted file mode 100644 index a0c40e59..00000000 --- a/requirements/dev.in +++ /dev/null @@ -1,3 +0,0 @@ --r test.in --r example.in -pip-tools diff --git a/requirements/dev.txt b/requirements/dev.txt deleted file mode 100644 index 187b4d3c..00000000 --- a/requirements/dev.txt +++ /dev/null @@ -1,58 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile requirements/dev.in -# -attrs==23.1.0 - # via pytest -build==1.0.3 - # via pip-tools -click==8.1.7 - # via pip-tools -coverage[toml]==7.2.7 - # via - # coverage - # pytest-cov -iniconfig==2.0.0 - # via pytest -numpy==1.26.3 - # via pandas -packaging==23.2 - # via - # build - # pytest -pandas==1.3.5 - # via -r requirements/example.in -pip-tools==6.14.0 - # via -r requirements/dev.in -pluggy==1.2.0 - # via pytest -prettytable==3.7.0 - # via -r requirements/example.in -py==1.11.0 - # via pytest -pyproject-hooks==1.0.0 - # via build -pytest==6.2.5 - # via - # -r requirements/test.in - # pytest-cov -pytest-cov==4.1.0 - # via -r requirements/test.in -python-dateutil==2.8.2 - # via pandas -pytz==2023.3.post1 - # via pandas -six==1.16.0 - # via python-dateutil -toml==0.10.2 - # via pytest -wcwidth==0.2.8 - # via prettytable -wheel==0.41.2 - # via pip-tools - -# The following packages are considered to be unsafe in a requirements file: -# pip -# setuptools diff --git a/requirements/example.in b/requirements/example.in deleted file mode 100644 index e3888460..00000000 --- a/requirements/example.in +++ /dev/null @@ -1,2 +0,0 @@ -prettytable -pandas diff --git a/requirements/example.txt b/requirements/example.txt deleted file mode 100644 index 34d8c655..00000000 --- a/requirements/example.txt +++ /dev/null @@ -1,20 +0,0 @@ -# -# This file is autogenerated by pip-compile with python 3.9 -# To update, run: -# -# pip-compile requirements/example.in -# -numpy==1.23.4 - # via pandas -pandas==1.5.0 - # via -r requirements/example.in -prettytable==2.4.0 - # via -r requirements/example.in -python-dateutil==2.8.2 - # via pandas -pytz==2022.4 - # via pandas -six==1.16.0 - # via python-dateutil -wcwidth==0.2.5 - # via prettytable diff --git a/requirements/test.in b/requirements/test.in deleted file mode 100644 index 9955decc..00000000 --- a/requirements/test.in +++ /dev/null @@ -1,2 +0,0 @@ -pytest -pytest-cov diff --git a/requirements/test.txt b/requirements/test.txt deleted file mode 100644 index 8d0b880f..00000000 --- a/requirements/test.txt +++ /dev/null @@ -1,22 +0,0 @@ -# -# This file is autogenerated by pip-compile with python 3.8 -# To update, run: -# -# pip-compile requirements/test.in -# -attrs==21.2.0 - # via pytest -iniconfig==1.1.1 - # via pytest -packaging==21.2 - # via pytest -pluggy==1.0.0 - # via pytest -py==1.11.0 - # via pytest -pyparsing==2.4.7 - # via packaging -pytest==6.2.5 - # via -r requirements/test.in -toml==0.10.2 - # via pytest diff --git a/setup.py b/setup.py deleted file mode 100644 index 7bc39bea..00000000 --- a/setup.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2020 vesoft inc. All rights reserved. -# -# This source code is licensed under Apache 2.0 License. - - -from setuptools import setup, find_packages -from pathlib import Path - -base_dir = Path(__file__).parent -long_description = (base_dir / 'README.md').read_text() - - -setup( - name='nebula3-python', - version='3.4.0', - license='Apache 2.0', - author='vesoft-inc', - author_email='info@vesoft.com', - description='Python client for NebulaGraph V3.4', - long_description=long_description, - long_description_content_type='text/markdown', - url='https://github.com/vesoft-inc/nebula-python', - install_requires=[ - 'httplib2 >= 0.20.0', - 'future >= 0.18.0', - 'six >= 1.16.0', - 'pytz >= 2021.1', - ], - packages=find_packages(), - platforms=['3.9, 3.10, 3.11, 3.12'], - package_dir={'nebula3': 'nebula3'}, -) diff --git a/tests/test_connection.py b/tests/test_connection.py index 0385c525..fead1345 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -6,20 +6,14 @@ # This source code is licensed under Apache 2.0 License. -import sys -import os import time - -current_dir = os.path.dirname(os.path.abspath(__file__)) -root_dir = os.path.join(current_dir, '..') -sys.path.insert(0, root_dir) - from unittest import TestCase -from nebula3.gclient.net import Connection + from nebula3.common import ttypes from nebula3.Exception import IOErrorException +from nebula3.gclient.net import Connection -AddrIp = ['127.0.0.1', '::1'] +AddrIp = ["127.0.0.1", "::1"] port = 9669 @@ -29,7 +23,7 @@ def test_create(self): try: conn = Connection() conn.open(ip, port, 1000) - auth_result = conn.authenticate('root', 'nebula') + auth_result = conn.authenticate("root", "nebula") assert auth_result.get_session_id() != 0 conn.close() except Exception as ex: @@ -40,15 +34,15 @@ def test_release(self): try: conn = Connection() conn.open(ip, port, 1000) - auth_result = conn.authenticate('root', 'nebula') + auth_result = conn.authenticate("root", "nebula") session_id = auth_result.get_session_id() assert session_id != 0 - resp = conn.execute(session_id, 'SHOW SPACES') + resp = conn.execute(session_id, "SHOW SPACES") assert resp.error_code == ttypes.ErrorCode.SUCCEEDED, resp.error_msg conn.signout(session_id) # the session delete later time.sleep(12) - resp = conn.execute(session_id, 'SHOW SPACES') + resp = conn.execute(session_id, "SHOW SPACES") assert resp.error_code != ttypes.ErrorCode.SUCCEEDED conn.close() except Exception as ex: @@ -58,10 +52,10 @@ def test_close(self): for ip in AddrIp: conn = Connection() conn.open(ip, port, 1000) - auth_result = conn.authenticate('root', 'nebula') + auth_result = conn.authenticate("root", "nebula") assert auth_result.get_session_id() != 0 conn.close() try: - conn.authenticate('root', 'nebula') + conn.authenticate("root", "nebula") except IOErrorException: assert True diff --git a/tests/test_data_from_server.py b/tests/test_data_from_server.py index ad197991..ed6975a2 100644 --- a/tests/test_data_from_server.py +++ b/tests/test_data_from_server.py @@ -6,19 +6,14 @@ # This source code is licensed under Apache 2.0 License. -from unittest import TestCase -from nebula3.gclient.net import ConnectionPool -from nebula3.data.DataObject import DateTimeWrapper, DateWrapper, TimeWrapper, Null -from nebula3.common.ttypes import DateTime, Date, Time, ErrorCode -from nebula3.Config import Config -import sys -import os -import time import json +import time +from unittest import TestCase -current_dir = os.path.dirname(os.path.abspath(__file__)) -root_dir = os.path.join(current_dir, '..') -sys.path.insert(0, root_dir) +from nebula3.common.ttypes import Date, DateTime, ErrorCode, Time +from nebula3.Config import Config +from nebula3.data.DataObject import DateTimeWrapper, DateWrapper, Null, TimeWrapper +from nebula3.gclient.net import ConnectionPool class TestBaseCase(TestCase): @@ -31,22 +26,22 @@ def setUpClass(cls) -> None: configs = Config() configs.max_connection_pool_size = 1 cls.pool = ConnectionPool() - cls.pool.init([('127.0.0.1', 9671)], configs) - cls.session = cls.pool.get_session('root', 'nebula') + cls.pool.init([("127.0.0.1", 9671)], configs) + cls.session = cls.pool.get_session("root", "nebula") resp = cls.session.execute( - ''' + """ CREATE SPACE IF NOT EXISTS test_data(vid_type=FIXED_STRING(8)); USE test_data; - CREATE TAG IF NOT EXISTS person(name string, age int8, grade int16, - friends int32, book_num int64, birthday datetime, - start_school date, morning time, property double, - is_girl bool, child_name fixed_string(10), expend float, + CREATE TAG IF NOT EXISTS person(name string, age int8, grade int16, + friends int32, book_num int64, birthday datetime, + start_school date, morning time, property double, + is_girl bool, child_name fixed_string(10), expend float, first_out_city timestamp, hobby string); CREATE TAG IF NOT EXISTS student(name string, interval duration); CREATE EDGE IF NOT EXISTS like(likeness double); CREATE EDGE IF NOT EXISTS friend(start_year int, end_year int); CREATE TAG INDEX IF NOT EXISTS person_name_index ON person(name(8)); - ''' + """ ) assert resp.is_succeeded(), resp.error_msg() @@ -111,38 +106,38 @@ def tearDownClass(cls) -> None: def test_base_type(self): resp = self.session.execute( 'FETCH PROP ON person "Bob" YIELD person.name, person.age, person.grade,' - 'person.friends, person.book_num, person.birthday, ' - 'person.start_school, person.morning, ' - 'person.property, person.is_girl, person.child_name, ' - 'person.expend, person.first_out_city, person.hobby' + "person.friends, person.book_num, person.birthday, " + "person.start_school, person.morning, " + "person.property, person.is_girl, person.child_name, " + "person.expend, person.first_out_city, person.hobby" ) assert resp.is_succeeded(), resp.error_msg() - assert '' == resp.error_msg() + assert "" == resp.error_msg() assert resp.latency() > 0 - assert '' == resp.comment() + assert "" == resp.comment() assert ErrorCode.SUCCEEDED == resp.error_code() - assert 'test_data' == resp.space_name() + assert "test_data" == resp.space_name() assert not resp.is_empty() assert 1 == resp.row_size() names = [ - 'person.name', - 'person.age', - 'person.grade', - 'person.friends', - 'person.book_num', - 'person.birthday', - 'person.start_school', - 'person.morning', - 'person.property', - 'person.is_girl', - 'person.child_name', - 'person.expend', - 'person.first_out_city', - 'person.hobby', + "person.name", + "person.age", + "person.grade", + "person.friends", + "person.book_num", + "person.birthday", + "person.start_school", + "person.morning", + "person.property", + "person.is_girl", + "person.child_name", + "person.expend", + "person.first_out_city", + "person.hobby", ] assert names == resp.keys() - assert 'Bob' == resp.row_values(0)[0].as_string() + assert "Bob" == resp.row_values(0)[0].as_string() assert 10 == resp.row_values(0)[1].as_int() assert 3 == resp.row_values(0)[2].as_int() assert 10 == resp.row_values(0)[3].as_int() @@ -152,11 +147,11 @@ def test_base_type(self): DateTime(2010, 9, 10, 2, 8, 2, 0) ) assert ( - '2010-09-10T10:08:02.000000' + "2010-09-10T10:08:02.000000" == return_data_time_val.get_local_datetime_str() ) assert ( - 'utc datetime: 2010-09-10T02:08:02.000000, timezone_offset: 28800' + "utc datetime: 2010-09-10T02:08:02.000000, timezone_offset: 28800" == str(return_data_time_val) ) @@ -165,14 +160,14 @@ def test_base_type(self): expected_time_val = TimeWrapper(Time(23, 10, 0, 0)) return_time_val = resp.row_values(0)[7].as_time() assert expected_time_val == return_time_val - assert '07:10:00.000000' == return_time_val.get_local_time_str() - assert 'utc time: 23:10:00.000000, timezone_offset: 28800' == str( + assert "07:10:00.000000" == return_time_val.get_local_time_str() + assert "utc time: 23:10:00.000000, timezone_offset: 28800" == str( return_time_val ) assert 1000.0 == resp.row_values(0)[8].as_double() assert False == resp.row_values(0)[9].as_bool() - assert 'Hello Worl' == resp.row_values(0)[10].as_string() + assert "Hello Worl" == resp.row_values(0)[10].as_string() assert 100.0 == resp.row_values(0)[11].as_double() assert 1111 == resp.row_values(0)[12].as_int() assert Null(Null.__NULL__) == resp.row_values(0)[13].as_null() @@ -201,12 +196,12 @@ def test_map_type(self): assert resp.row_values(0)[0].is_map() val = resp.row_values(0)[0].as_map() assert len(val.keys()) == 3 - assert 'name' in val.keys() - assert val['name'].as_string() == 'Tom' - assert 'age' in val.keys() - assert val['age'].as_int() == 18 - assert 'birthday' in val.keys() - assert val['birthday'].as_string() == '2010-10-10' + assert "name" in val.keys() + assert val["name"].as_string() == "Tom" + assert "age" in val.keys() + assert val["age"].as_int() == 18 + assert "birthday" in val.keys() + assert val["birthday"].as_string() == "2010-10-10" def test_node_type(self): resp = self.session.execute('MATCH (v:person {name: "Bob"}) RETURN v') @@ -237,17 +232,17 @@ def test_path_type(self): path = resp.row_values(0)[0].as_path() expected_str = ( '("Bob" :student{interval: P1MT100.000020000S, name: "Bob"} :person{age:' - ' 10, birthday: utc datetime: 2010-09-10T02:08:02.000000, timezone_offset:' + " 10, birthday: utc datetime: 2010-09-10T02:08:02.000000, timezone_offset:" ' 28800, book_num: 100, child_name: "Hello Worl", expend: 100.0,' - ' first_out_city: 1111, friends: 10, grade: 3, hobby: __NULL__, is_girl:' - ' False, morning: utc time: 23:10:00.000000, timezone_offset: 28800, name:' + " first_out_city: 1111, friends: 10, grade: 3, hobby: __NULL__, is_girl:" + " False, morning: utc time: 23:10:00.000000, timezone_offset: 28800, name:" ' "Bob", property: 1000.0, start_school:' ' 2017-09-10})-[:friend@0{start_year: 2018, end_year: 2020}]->("Lily"' ' :student{interval: P12MT0.000000000S, name: "Lily"} :person{age: 9,' - ' birthday: utc datetime: 2010-09-10T02:08:02.000000, timezone_offset:' + " birthday: utc datetime: 2010-09-10T02:08:02.000000, timezone_offset:" ' 28800, book_num: 100, child_name: "Hello Worl", expend: 100.0,' - ' first_out_city: 1111, friends: 10, grade: 3, hobby: __NULL__, is_girl:' - ' False, morning: utc time: 23:10:00.000000, timezone_offset: 28800, name:' + " first_out_city: 1111, friends: 10, grade: 3, hobby: __NULL__, is_girl:" + " False, morning: utc time: 23:10:00.000000, timezone_offset: 28800, name:" ' "Lily", property: 1000.0, start_school: 2017-09-10})' ) assert expected_str == str(path) @@ -279,7 +274,7 @@ def test_complex_types(self): exp = [ { "person.age": 10, - "person.birthday": '2010-09-10T02:08:02.000000000Z', + "person.birthday": "2010-09-10T02:08:02.000000000Z", "person.book_num": 100, "person.child_name": "Hello Worl", "person.expend": 100, @@ -288,10 +283,10 @@ def test_complex_types(self): "person.grade": 3, "person.hobby": None, "person.is_girl": False, - "person.morning": '23:10:00.000000000Z', + "person.morning": "23:10:00.000000000Z", "person.name": "Bob", "person.property": 1000, - "person.start_school": '2017-09-10', + "person.start_school": "2017-09-10", "student.name": "Bob", "student.interval": "P1MT100.000020000S", } @@ -300,9 +295,7 @@ def test_complex_types(self): assert exp == json_obj["results"][0]["data"][0]["row"] def test_error(self): - resp = self.session.execute_json( - 'MATCH (v:invalidTag {name: \"Bob\"}) RETURN v' - ) + resp = self.session.execute_json('MATCH (v:invalidTag {name: "Bob"}) RETURN v') json_obj = json.loads(resp) diff --git a/tests/test_data_type.py b/tests/test_data_type.py index 0ea4050b..a457ef3b 100644 --- a/tests/test_data_type.py +++ b/tests/test_data_type.py @@ -6,47 +6,38 @@ # This source code is licensed under Apache 2.0 License. import copy -import sys -import os from datetime import date +from unittest import TestCase - -current_dir = os.path.dirname(os.path.abspath(__file__)) -root_dir = os.path.join(current_dir, '..') -sys.path.insert(0, root_dir) - -from nebula3.Exception import InvalidKeyException +from nebula3.common import ttypes from nebula3.common.ttypes import ( - Value, - NullType, - Time, - DateTime, - NSet, Date, - NList, - NMap, - Geography, + DateTime, Duration, ErrorCode, + NList, + NMap, + NSet, + NullType, + Time, + Value, ) -from nebula3.common import ttypes -from nebula3.graph import ttypes as graphTtype -from unittest import TestCase -from nebula3.data.ResultSet import ResultSet from nebula3.data.DataObject import ( - ValueWrapper, - Node, - Relationship, - PathWrapper, - TimeWrapper, + DataSetWrapper, DateTimeWrapper, DateWrapper, - Null, - Segment, - DataSetWrapper, - GeographyWrapper, DurationWrapper, + GeographyWrapper, + Node, + Null, + PathWrapper, + Relationship, + TimeWrapper, + ValueWrapper, ) +from nebula3.data.ResultSet import ResultSet +from nebula3.Exception import InvalidKeyException +from nebula3.graph import ttypes as graphTtype class TestBaseCase(TestCase): @@ -57,13 +48,13 @@ def get_vertex_value(cls, vid, empty_props=False): vertex.tags = list() for i in range(0, 3): tag = ttypes.Tag() - tag.name = ('tag{}'.format(i)).encode('utf-8') + tag.name = ("tag{}".format(i)).encode("utf-8") if not empty_props: tag.props = dict() for j in range(0, 5): value = ttypes.Value() value.set_iVal(j) - tag.props[('prop{}'.format(j)).encode('utf-8')] = value + tag.props[("prop{}".format(j)).encode("utf-8")] = value vertex.tags.append(tag) return vertex @@ -77,14 +68,14 @@ def get_edge_value(cls, src_id, dst_id, is_reverse=False, empty_props=False): edge.src = ttypes.Value(sVal=dst_id) edge.dst = ttypes.Value(sVal=src_id) edge.type = 1 - edge.name = b'classmate' + edge.name = b"classmate" edge.ranking = 100 if not empty_props: edge.props = dict() for i in range(0, 5): value = ttypes.Value() value.set_iVal(i) - edge.props[('prop{}'.format(i)).encode('utf-8')] = value + edge.props[("prop{}".format(i)).encode("utf-8")] = value return edge @classmethod @@ -94,15 +85,15 @@ def get_path_value(cls, start_id, steps=5): path.steps = list() for i in range(0, steps): step = ttypes.Step() - step.dst = cls.get_vertex_value(('vertex{}'.format(i)).encode('utf-8')) + step.dst = cls.get_vertex_value(("vertex{}".format(i)).encode("utf-8")) step.type = 1 if i % 2 == 0 else -1 - step.name = b'classmate' + step.name = b"classmate" step.ranking = 100 step.props = dict() for i in range(0, 5): value = ttypes.Value() value.set_iVal(i) - step.props[('prop{}'.format(i)).encode('utf-8')] = value + step.props[("prop{}".format(i)).encode("utf-8")] = value path.steps.append(step) return path @@ -251,7 +242,7 @@ def test_as_double(self): def test_as_string(self): value = ttypes.Value() - value.set_sVal(b'Tom') + value.set_sVal(b"Tom") value_wrapper = ValueWrapper(value) assert value_wrapper.is_string() @@ -349,12 +340,12 @@ def test_cast(self): map_val.set_mVal(tmp_map_val) node_val = ttypes.Value() - node_val.set_vVal(self.get_vertex_value(b'Tom')) + node_val.set_vVal(self.get_vertex_value(b"Tom")) - relationship_val = ttypes.Value(eVal=self.get_edge_value(b'Tom', b'Lily')) + relationship_val = ttypes.Value(eVal=self.get_edge_value(b"Tom", b"Lily")) path_val = ttypes.Value() - path_val.set_pVal(self.get_path_value(b'Tom')) + path_val.set_pVal(self.get_path_value(b"Tom")) tmp_list_val = NList() tmp_list_val.values = [ @@ -407,8 +398,8 @@ def test_as_time(self): assert time_val.get_minute() == 20 assert time_val.get_sec() == 10 assert time_val.get_microsec() == 100 - assert 'utc time: 10:20:10.000100, timezone_offset: 28800' == str(time_val) - assert '18:20:10.000100' == time_val.get_local_time_str() + assert "utc time: 10:20:10.000100, timezone_offset: 28800" == str(time_val) + assert "18:20:10.000100" == time_val.get_local_time_str() new_time = copy.deepcopy(time) new_time.hour = 18 assert new_time == time_val.get_local_time() @@ -431,7 +422,7 @@ def test_as_date(self): assert date_val.get_year() == 220 assert date_val.get_month() == 2 assert date_val.get_day() == 10 - assert '220-02-10' == str(date_val) + assert "220-02-10" == str(date_val) def test_as_datetime(self): datetime = DateTime() @@ -453,10 +444,10 @@ def test_as_datetime(self): assert datetime_val.get_minute() == 20 assert datetime_val.get_sec() == 10 assert datetime_val.get_microsec() == 100 - assert 'utc datetime: 123-02-01T10:20:10.000100, timezone_offset: 28800' == str( + assert "utc datetime: 123-02-01T10:20:10.000100, timezone_offset: 28800" == str( datetime_val ) - assert '123-02-01T18:20:10.000100' == datetime_val.get_local_datetime_str() + assert "123-02-01T18:20:10.000100" == datetime_val.get_local_datetime_str() new_datetime = copy.deepcopy(datetime) new_datetime.hour = 18 assert new_datetime == datetime_val.get_local_datetime() @@ -469,30 +460,30 @@ def test_as_datetime(self): def test_as_node(self): value = ttypes.Value() - value.set_vVal(self.get_vertex_value(b'Tom')) + value.set_vVal(self.get_vertex_value(b"Tom")) value_wrapper = ValueWrapper(value) assert value_wrapper.is_vertex() node = value_wrapper.as_node() assert isinstance(node, Node) - assert node.get_id().as_string() == 'Tom' - assert node.has_tag('tag1') + assert node.get_id().as_string() == "Tom" + assert node.has_tag("tag1") assert ( - node.prop_names('tag1').sort() - == ['prop0', 'prop1', 'prop2', 'prop3', 'prop4'].sort() + node.prop_names("tag1").sort() + == ["prop0", "prop1", "prop2", "prop3", "prop4"].sort() ) - expect_values = [(v.as_int()) for v in node.prop_values('tag1')] + expect_values = [(v.as_int()) for v in node.prop_values("tag1")] assert expect_values == [0, 1, 2, 3, 4] - assert node.tags() == ['tag0', 'tag1', 'tag2'] + assert node.tags() == ["tag0", "tag1", "tag2"] assert ( - list(node.properties('tag1').keys()).sort() - == ['prop0', 'prop1', 'prop2', 'prop3', 'prop4'].sort() + list(node.properties("tag1").keys()).sort() + == ["prop0", "prop1", "prop2", "prop3", "prop4"].sort() ) - expect_values = [(v.as_int()) for v in node.properties('tag1').values()] + expect_values = [(v.as_int()) for v in node.properties("tag1").values()] assert expect_values == [0, 1, 2, 3, 4] def test_as_relationship(self): - value = ttypes.Value(eVal=self.get_edge_value(b'Tom', b'Lily')) + value = ttypes.Value(eVal=self.get_edge_value(b"Tom", b"Lily")) value_wrapper = ValueWrapper(value) assert value_wrapper.is_edge() @@ -500,36 +491,36 @@ def test_as_relationship(self): assert isinstance(relationship, Relationship) # test with reversely - reversely_value = ttypes.Value(eVal=self.get_edge_value(b'Lily', b'Tom', True)) + reversely_value = ttypes.Value(eVal=self.get_edge_value(b"Lily", b"Tom", True)) reversely_value_wrapper = ValueWrapper(reversely_value) reversely_relationship = reversely_value_wrapper.as_relationship() assert isinstance(reversely_relationship, Relationship) assert reversely_relationship == relationship # test with reversely no equal - reversely_value = ttypes.Value(eVal=self.get_edge_value(b'Tom', b'Lily', True)) + reversely_value = ttypes.Value(eVal=self.get_edge_value(b"Tom", b"Lily", True)) reversely_value_wrapper = ValueWrapper(reversely_value) reversely_relationship = reversely_value_wrapper.as_relationship() assert isinstance(reversely_relationship, Relationship) assert reversely_relationship != relationship relationship.ranking() == 100 - relationship.edge_name() == 'classmate' - relationship.start_vertex_id().as_string() == 'Lily' - relationship.start_vertex_id().as_string() == 'Tom' - assert relationship.keys() == ['prop0', 'prop1', 'prop2', 'prop3', 'prop4'] + relationship.edge_name() == "classmate" + relationship.start_vertex_id().as_string() == "Lily" + relationship.start_vertex_id().as_string() == "Tom" + assert relationship.keys() == ["prop0", "prop1", "prop2", "prop3", "prop4"] expect_values = [(v.as_int()) for v in relationship.values()] assert expect_values == [0, 1, 2, 3, 4] assert ( list(relationship.properties().keys()).sort() - == ['prop0', 'prop1', 'prop2', 'prop3', 'prop4'].sort() + == ["prop0", "prop1", "prop2", "prop3", "prop4"].sort() ) expect_values = [(v.as_int()) for v in relationship.properties().values()] assert expect_values == [0, 1, 2, 3, 4] # test empty props value = ttypes.Value( - eVal=self.get_edge_value(b'Tom', b'Lily', empty_props=True) + eVal=self.get_edge_value(b"Tom", b"Lily", empty_props=True) ) relationship = ValueWrapper(value).as_relationship() assert relationship.keys() == [] @@ -538,7 +529,7 @@ def test_as_relationship(self): def test_as_path(self): value = ttypes.Value() - value.set_pVal(self.get_path_value(b'Tom')) + value.set_pVal(self.get_path_value(b"Tom")) value_wrapper = ValueWrapper(value) assert value_wrapper.is_path() @@ -562,95 +553,95 @@ def test_as_duration(self): duration = value_wrapper.as_duration() assert isinstance(duration, DurationWrapper) - assert str(duration) == 'P12MT86400.003000000S' + assert str(duration) == "P12MT86400.003000000S" class TestNode(TestBaseCase): def test_node_api(self): test_set = set() test_set.add(Value()) - node = Node(self.get_vertex_value(b'Tom')) - assert 'Tom' == node.get_id().as_string() + node = Node(self.get_vertex_value(b"Tom")) + assert "Tom" == node.get_id().as_string() - assert node.has_tag('tag2') + assert node.has_tag("tag2") - assert ['prop0', 'prop1', 'prop2', 'prop3', 'prop4'] == node.prop_names('tag2') + assert ["prop0", "prop1", "prop2", "prop3", "prop4"] == node.prop_names("tag2") assert [0, 1, 2, 3, 4] == [ - (value.as_int()) for value in node.prop_values('tag2') + (value.as_int()) for value in node.prop_values("tag2") ] - assert ['tag0', 'tag1', 'tag2'] == node.tags() + assert ["tag0", "tag1", "tag2"] == node.tags() expect_properties = {} - for key in node.properties('tag2').keys(): - expect_properties[key] = node.properties('tag2')[key].as_int() + for key in node.properties("tag2").keys(): + expect_properties[key] = node.properties("tag2")[key].as_int() assert { - 'prop0': 0, - 'prop1': 1, - 'prop2': 2, - 'prop3': 3, - 'prop4': 4, + "prop0": 0, + "prop1": 1, + "prop2": 2, + "prop3": 3, + "prop4": 4, } == expect_properties class TestRelationship(TestBaseCase): def test_relationship_api(self): - relationship = Relationship(self.get_edge_value(b'Tom', b'Lily')) + relationship = Relationship(self.get_edge_value(b"Tom", b"Lily")) - assert 'Tom' == relationship.start_vertex_id().as_string() + assert "Tom" == relationship.start_vertex_id().as_string() - assert 'Lily' == relationship.end_vertex_id().as_string() + assert "Lily" == relationship.end_vertex_id().as_string() assert 100 == relationship.ranking() assert 100 == relationship.ranking() - assert 'classmate' == relationship.edge_name() + assert "classmate" == relationship.edge_name() - assert ['prop0', 'prop1', 'prop2', 'prop3', 'prop4'] == relationship.keys() + assert ["prop0", "prop1", "prop2", "prop3", "prop4"] == relationship.keys() expect_properties = {} for key in relationship.properties().keys(): expect_properties[key] = relationship.properties()[key].as_int() assert { - 'prop0': 0, - 'prop1': 1, - 'prop2': 2, - 'prop3': 3, - 'prop4': 4, + "prop0": 0, + "prop1": 1, + "prop2": 2, + "prop3": 3, + "prop4": 4, } == expect_properties class TestPath(TestBaseCase): def test_path_api(self): - path = PathWrapper(self.get_path_value(b'Tom')) - assert Node(self.get_vertex_value(b'Tom')) == path.start_node() + path = PathWrapper(self.get_path_value(b"Tom")) + assert Node(self.get_vertex_value(b"Tom")) == path.start_node() assert 5 == path.length() - assert path.contain_node(Node(self.get_vertex_value(b'vertex3'))) + assert path.contain_node(Node(self.get_vertex_value(b"vertex3"))) assert path.contain_relationship( - Relationship(self.get_edge_value(b'vertex3', b'vertex2')) + Relationship(self.get_edge_value(b"vertex3", b"vertex2")) ) nodes = list() nodes.append(path.start_node()) for i in range(0, 5): nodes.append( - Node(self.get_vertex_value(('vertex'.format(i)).encode('utf-8'))) + Node(self.get_vertex_value(("vertex".format()).encode("utf-8"))) ) relationships = list() - relationships.append(Relationship(self.get_edge_value(b'Tom', b'vertex0'))) + relationships.append(Relationship(self.get_edge_value(b"Tom", b"vertex0"))) for i in range(0, 4): if i % 2 == 0: relationships.append( Relationship( self.get_edge_value( - ('vertex{}'.format(i + 1)).encode('utf-8'), - ('vertex{}'.format(i)).encode('utf-8'), + ("vertex{}".format(i + 1)).encode("utf-8"), + ("vertex{}".format(i)).encode("utf-8"), ) ) ) @@ -658,8 +649,8 @@ def test_path_api(self): relationships.append( Relationship( self.get_edge_value( - ('vertex{}'.format(i)).encode('utf-8'), - ('vertex{}'.format(i + 1)).encode('utf-8'), + ("vertex{}".format(i)).encode("utf-8"), + ("vertex{}".format(i + 1)).encode("utf-8"), ) ) ) @@ -744,17 +735,17 @@ def test_all(self): assert data_set_wrapper1.column_values("col6_string")[0].is_string() assert ( data_set_wrapper1.column_values("col6_string")[0].as_string() - == 'hello world' + == "hello world" ) assert ( data_set_wrapper1.column_values("col6_string")[1].as_string() - == 'hello world' + == "hello world" ) assert data_set_wrapper1.row_values(0)[5].is_string() assert data_set_wrapper1.row_values(1)[5].is_string() - assert data_set_wrapper1.row_values(0)[5].as_string() == 'hello world' - assert data_set_wrapper1.row_values(1)[5].as_string() == 'hello world' + assert data_set_wrapper1.row_values(0)[5].as_string() == "hello world" + assert data_set_wrapper1.row_values(1)[5].as_string() == "hello world" class TestResultset(TestBaseCase): @@ -850,17 +841,17 @@ def test_all_interface(self): assert record.get_value(1).as_null() == Null(Null.BAD_DATA) null_value = Value(nVal=Null.BAD_DATA) assert record.get_value(1) == ValueWrapper(null_value) - assert str(record.get_value(1).as_null()) == 'BAD_DATA' + assert str(record.get_value(1).as_null()) == "BAD_DATA" # test get_value_by_key() - assert record.get_value_by_key('col2_null').is_null() - assert record.get_value_by_key('col3_bool').is_bool() - assert not record.get_value_by_key('col3_bool').as_bool() + assert record.get_value_by_key("col2_null").is_null() + assert record.get_value_by_key("col3_bool").is_bool() + assert not record.get_value_by_key("col3_bool").as_bool() # get_value_by_key with not exited key try: - record.get_value_by_key('not existed') - assert False, 'Not expect here' + record.get_value_by_key("not existed") + assert False, "Not expect here" except InvalidKeyException as e: assert True assert e.message == "KeyError: `not existed'" diff --git a/tests/test_graph_storage_client.py b/tests/test_graph_storage_client.py index 66be4656..99d7a0bb 100644 --- a/tests/test_graph_storage_client.py +++ b/tests/test_graph_storage_client.py @@ -6,32 +6,26 @@ # This source code is licensed under Apache 2.0 License. -import random -import sys +import logging import os +import random import time -import logging import pytest -current_dir = os.path.dirname(os.path.abspath(__file__)) -root_dir = os.path.join(current_dir, '..') -sys.path.insert(0, root_dir) - from nebula3.Exception import ( EdgeNotFoundException, - TagNotFoundException, - SpaceNotFoundException, PartNotFoundException, + SpaceNotFoundException, + TagNotFoundException, ) - -from nebula3.sclient.BaseResult import EdgeData -from nebula3.sclient.ScanResult import VertexData +from nebula3.gclient.net import Connection from nebula3.mclient import MetaCache +from nebula3.sclient.BaseResult import EdgeData from nebula3.sclient.GraphStorageClient import GraphStorageClient -from nebula3.gclient.net import Connection +from nebula3.sclient.ScanResult import VertexData -logging.basicConfig(level=logging.INFO, format='[%(asctime)s]:%(message)s') +logging.basicConfig(level=logging.INFO, format="[%(asctime)s]:%(message)s") class TestGraphStorageClient(object): @@ -43,53 +37,53 @@ def execute_with_retry(conn, session_id, stmt, retry=3): resp = conn.execute(session_id, stmt) if resp.error_code == 0: return - assert False, 'Execute `{}` failed: {}'.format( - stmt, resp.error_msg.decode('utf-8') + assert False, "Execute `{}` failed: {}".format( + stmt, resp.error_msg.decode("utf-8") ) @classmethod def setup_class(cls): try: conn = Connection() - conn.open('127.0.0.1', 9671, 3000) + conn.open("127.0.0.1", 9671, 3000) - auth_result = conn.authenticate('root', 'nebula') + auth_result = conn.authenticate("root", "nebula") session_id = auth_result.get_session_id() assert session_id != 0 cls.execute_with_retry( conn, session_id, - 'CREATE SPACE IF NOT EXISTS test_graph_storage_client(' - 'PARTITION_NUM=10,' - 'REPLICA_FACTOR=1,' - 'vid_type=FIXED_STRING(20));' - 'USE test_graph_storage_client;' - 'CREATE TAG IF NOT EXISTS person(name string, age int);' - 'CREATE EDGE IF NOT EXISTS friend(start int, end int);', + "CREATE SPACE IF NOT EXISTS test_graph_storage_client(" + "PARTITION_NUM=10," + "REPLICA_FACTOR=1," + "vid_type=FIXED_STRING(20));" + "USE test_graph_storage_client;" + "CREATE TAG IF NOT EXISTS person(name string, age int);" + "CREATE EDGE IF NOT EXISTS friend(start int, end int);", ) time.sleep(5) for id in range(1000): - vid = 'person' + str(id) + vid = "person" + str(id) cmd = ( - 'INSERT VERTEX person(name, age) ' - 'VALUES \"{}\":(\"{}\", {})'.format(vid, vid, id) + "INSERT VERTEX person(name, age) " + 'VALUES "{}":("{}", {})'.format(vid, vid, id) ) cls.execute_with_retry(conn, session_id, cmd) for id in range(1000): - src_id = 'person' + str(id) - dst_id = 'person' + str(1000 - id) + src_id = "person" + str(id) + dst_id = "person" + str(1000 - id) start = random.randint(2000, 2010) end = random.randint(2010, 2020) cmd = ( - 'INSERT EDGE friend(start, end) ' - 'VALUES \"{}\"->\"{}\":({}, {})'.format(src_id, dst_id, start, end) + "INSERT EDGE friend(start, end) " + 'VALUES "{}"->"{}":({}, {})'.format(src_id, dst_id, start, end) ) cls.execute_with_retry(conn, session_id, cmd) conn.close() meta_cache = MetaCache( - [('172.28.1.1', 9559), ('172.28.1.2', 9559), ('172.28.1.3', 9559)], + [("172.28.1.1", 9559), ("172.28.1.2", 9559), ("172.28.1.3", 9559)], 50000, ) cls.graph_storage_client = GraphStorageClient(meta_cache) @@ -103,7 +97,7 @@ def setup_class(cls): def test_scan_tag_with_no_existed_space_name(self): try: self.graph_storage_client.scan_vertex( - space_name='not_existed', tag_name='person', limit=1 + space_name="not_existed", tag_name="person", limit=1 ) assert False except SpaceNotFoundException: @@ -114,9 +108,9 @@ def test_scan_tag_with_no_existed_space_name(self): def test_scan_tag_with_no_existed_part_id(self): try: self.graph_storage_client.scan_vertex_with_part( - space_name='test_graph_storage_client', + space_name="test_graph_storage_client", part=3000, - tag_name='person', + tag_name="person", limit=1, ) assert False @@ -127,7 +121,7 @@ def test_scan_tag_with_no_existed_part_id(self): def test_scan_vertex_data(self): resp = self.graph_storage_client.scan_vertex( - space_name='test_graph_storage_client', tag_name='person', limit=1 + space_name="test_graph_storage_client", tag_name="person", limit=1 ) assert resp.has_next() result = resp.next() @@ -135,10 +129,10 @@ def test_scan_vertex_data(self): data_set = result.get_data_set_wrapper() assert data_set.get_row_size() == 10 assert data_set.get_col_names() == [ - '_vid', - 'person._vid', - 'person.name', - 'person.age', + "_vid", + "person._vid", + "person.name", + "person.age", ] # test as nodes @@ -149,27 +143,27 @@ def test_scan_vertex_data(self): for vertex in result: count += 1 assert isinstance(vertex, VertexData) - assert vertex.get_id().as_string().find('person') >= 0 + assert vertex.get_id().as_string().find("person") >= 0 # test get_prop_values prop_values = vertex.get_prop_values() assert len(prop_values) == 2 assert prop_values[0].is_string() - assert prop_values[0].as_string().find('person') >= 0 + assert prop_values[0].as_string().find("person") >= 0 assert prop_values[1].is_int() assert prop_values[1].as_int() >= 0 # test as node node = vertex.as_node() - assert node.prop_names('person') == ['name', 'age'] - assert node.tags() == ['person'] - assert node.get_id().as_string().find('person') >= 0 + assert node.prop_names("person") == ["name", "age"] + assert node.tags() == ["person"] + assert node.get_id().as_string().find("person") >= 0 assert count > 1 - @pytest.mark.skip(reason='cannot test with next cursor yet') + @pytest.mark.skip(reason="cannot test with next cursor yet") def test_scan_vertex(self): # test get all by once resp = self.graph_storage_client.scan_vertex( - space_name='test_graph_storage_client', tag_name='person', limit=2000 + space_name="test_graph_storage_client", tag_name="person", limit=2000 ) next_count = 0 result1 = [] @@ -183,7 +177,7 @@ def test_scan_vertex(self): # test with cursor resp = self.graph_storage_client.scan_vertex( - space_name='test_graph_storage_client', tag_name='person', limit=10 + space_name="test_graph_storage_client", tag_name="person", limit=10 ) next_count = 0 result2 = [] @@ -199,7 +193,7 @@ def test_scan_vertex(self): def test_scan_tag_with_no_existed_tag_name(self): try: resp = self.graph_storage_client.scan_vertex( - space_name='test_graph_storage_client', tag_name='not_existed', limit=1 + space_name="test_graph_storage_client", tag_name="not_existed", limit=1 ) assert False except TagNotFoundException: @@ -209,19 +203,19 @@ def test_scan_tag_with_no_existed_tag_name(self): def test_scan_edge_data(self): resp = self.graph_storage_client.scan_edge( - space_name='test_graph_storage_client', edge_name='friend', limit=1 + space_name="test_graph_storage_client", edge_name="friend", limit=1 ) assert resp.has_next() result = resp.next() data_set = result.get_data_set_wrapper() assert data_set.get_row_size() == 10 assert data_set.get_col_names() == [ - 'friend._src', - 'friend._type', - 'friend._rank', - 'friend._dst', - 'friend.start', - 'friend.end', + "friend._src", + "friend._type", + "friend._rank", + "friend._dst", + "friend.start", + "friend.end", ] # test as edge assert len(result.as_relationships()) >= 10 @@ -232,10 +226,10 @@ def test_scan_edge_data(self): count += 1 assert isinstance(edge, EdgeData) relationship = edge.as_relationship() - assert relationship.keys() == ['start', 'end'] - assert relationship.edge_name() == 'friend' - assert relationship.start_vertex_id().as_string().find('person') >= 0 - assert relationship.end_vertex_id().as_string().find('person') >= 0 + assert relationship.keys() == ["start", "end"] + assert relationship.edge_name() == "friend" + assert relationship.start_vertex_id().as_string().find("person") >= 0 + assert relationship.end_vertex_id().as_string().find("person") >= 0 # test get_prop_values prop_values = edge.get_prop_values() assert len(prop_values) == 2 @@ -245,11 +239,11 @@ def test_scan_edge_data(self): assert prop_values[1].as_int() >= 2010 assert count > 1 - @pytest.mark.skip(reason='cannot test with next cursor yet') + @pytest.mark.skip(reason="cannot test with next cursor yet") def test_scan_edge(self): # test get all by once resp = self.graph_storage_client.scan_edge( - space_name='test_graph_storage_client', edge_name='friend', limit=2000 + space_name="test_graph_storage_client", edge_name="friend", limit=2000 ) next_count = 0 while resp.has_next(): @@ -261,7 +255,7 @@ def test_scan_edge(self): # test with cursor resp = self.graph_storage_client.scan_edge( - space_name='test_graph_storage_client', edge_name='friend', limit=10 + space_name="test_graph_storage_client", edge_name="friend", limit=10 ) next_count = 0 while resp.has_next(): @@ -274,7 +268,7 @@ def test_scan_edge(self): def test_scan_edge_with_no_existed_edge_name(self): try: self.graph_storage_client.scan_edge( - space_name='test_graph_storage_client', edge_name='not_existed', limit=1 + space_name="test_graph_storage_client", edge_name="not_existed", limit=1 ) assert False except EdgeNotFoundException: @@ -285,8 +279,8 @@ def test_scan_edge_with_no_existed_edge_name(self): def test_scan_edge_with_leader(self): try: resp = self.graph_storage_client.scan_edge( - space_name='test_graph_storage_client', - edge_name='friend', + space_name="test_graph_storage_client", + edge_name="friend", limit=2000, enable_read_from_follower=False, ) @@ -295,11 +289,11 @@ def test_scan_edge_with_leader(self): @pytest.mark.skip(reason="nebula-storage is not return the leader address") def test_scan_edge_with_leader_change(self): - os.system('docker stop nebula-docker-compose_storaged0_1') + os.system("docker stop nebula-docker-compose_storaged0_1") try: resp = self.graph_storage_client.scan_edge( - space_name='test_graph_storage_client', - edge_name='friend', + space_name="test_graph_storage_client", + edge_name="friend", limit=2000, enable_read_from_follower=False, ) @@ -313,4 +307,4 @@ def test_scan_edge_with_leader_change(self): except Exception as e: assert False, e finally: - os.system('docker start nebula-docker-compose_storaged0_1') + os.system("docker start nebula-docker-compose_storaged0_1") diff --git a/tests/test_meta_cache.py b/tests/test_meta_cache.py index dc492233..26fc061b 100644 --- a/tests/test_meta_cache.py +++ b/tests/test_meta_cache.py @@ -6,17 +6,11 @@ # This source code is licensed under Apache 2.0 License. -import sys -import os import time -current_dir = os.path.dirname(os.path.abspath(__file__)) -root_dir = os.path.join(current_dir, '..') -sys.path.insert(0, root_dir) - +from nebula3.common import ttypes from nebula3.gclient.net import Connection from nebula3.mclient import MetaCache -from nebula3.common import ttypes class TestMetaCache(object): @@ -25,118 +19,118 @@ def setup_class(cls): # create schema try: conn = Connection() - conn.open('127.0.0.1', 9669, 1000) - auth_result = conn.authenticate('root', 'nebula') + conn.open("127.0.0.1", 9669, 1000) + auth_result = conn.authenticate("root", "nebula") session_id = auth_result.get_session_id() assert session_id != 0 resp = conn.execute( session_id, - 'CREATE SPACE IF NOT EXISTS test_meta_cache1(REPLICA_FACTOR=3, vid_type=FIXED_STRING(8));' - 'USE test_meta_cache1;' - 'CREATE TAG IF NOT EXISTS tag11(name string);' - 'CREATE EDGE IF NOT EXISTS edge11(name string);' - 'CREATE SPACE IF NOT EXISTS test_meta_cache2(vid_type=FIXED_STRING(8));' - 'USE test_meta_cache2;' - 'CREATE TAG IF NOT EXISTS tag22(name string);' - 'CREATE EDGE IF NOT EXISTS edge22(name string);', + "CREATE SPACE IF NOT EXISTS test_meta_cache1(REPLICA_FACTOR=3, vid_type=FIXED_STRING(8));" + "USE test_meta_cache1;" + "CREATE TAG IF NOT EXISTS tag11(name string);" + "CREATE EDGE IF NOT EXISTS edge11(name string);" + "CREATE SPACE IF NOT EXISTS test_meta_cache2(vid_type=FIXED_STRING(8));" + "USE test_meta_cache2;" + "CREATE TAG IF NOT EXISTS tag22(name string);" + "CREATE EDGE IF NOT EXISTS edge22(name string);", ) assert resp.error_code == 0 conn.close() time.sleep(10) cls.meta_cache = MetaCache( - [('127.0.0.1', 9559), ('127.0.0.1', 9560), ('127.0.0.1', 9561)], 50000 + [("127.0.0.1", 9559), ("127.0.0.1", 9560), ("127.0.0.1", 9561)], 50000 ) - except Exception as x: + except Exception: import traceback print(traceback.format_exc()) assert False def test_get_space_id(self): - space_id1 = self.meta_cache.get_space_id('test_meta_cache1') - space_id2 = self.meta_cache.get_space_id('test_meta_cache2') + space_id1 = self.meta_cache.get_space_id("test_meta_cache1") + space_id2 = self.meta_cache.get_space_id("test_meta_cache2") assert 0 < space_id1 < space_id2 # test not existed try: space_id = self.meta_cache.get_tag_id( - 'test_meta_cache1', 'space_not_existed' + "test_meta_cache1", "space_not_existed" ) assert False except Exception: assert True def test_get_tag_id(self): - tag_id1 = self.meta_cache.get_tag_id('test_meta_cache1', 'tag11') - tag_id2 = self.meta_cache.get_tag_id('test_meta_cache2', 'tag22') + tag_id1 = self.meta_cache.get_tag_id("test_meta_cache1", "tag11") + tag_id2 = self.meta_cache.get_tag_id("test_meta_cache2", "tag22") assert 0 < tag_id1 < tag_id2 # test not existed try: - tag_id = self.meta_cache.get_tag_id('test_meta_cache1', 'tag_not_existed') + tag_id = self.meta_cache.get_tag_id("test_meta_cache1", "tag_not_existed") assert False except Exception: assert True def test_get_edge_type(self): - edge_id1 = self.meta_cache.get_edge_type('test_meta_cache1', 'edge11') - edge_id2 = self.meta_cache.get_edge_type('test_meta_cache2', 'edge22') + edge_id1 = self.meta_cache.get_edge_type("test_meta_cache1", "edge11") + edge_id2 = self.meta_cache.get_edge_type("test_meta_cache2", "edge22") assert 0 < edge_id1 < edge_id2 # test not existed try: edge_id = self.meta_cache.get_edge_type( - 'test_meta_cache1', 'edge_not_existed' + "test_meta_cache1", "edge_not_existed" ) assert False except Exception: assert True def test_get_tag_schema(self): - tag_schema1 = self.meta_cache.get_tag_schema('test_meta_cache1', 'tag11') - tag_schema2 = self.meta_cache.get_tag_schema('test_meta_cache2', 'tag22') - assert tag_schema1.columns[0].name.decode('utf-8') == 'name' + tag_schema1 = self.meta_cache.get_tag_schema("test_meta_cache1", "tag11") + tag_schema2 = self.meta_cache.get_tag_schema("test_meta_cache2", "tag22") + assert tag_schema1.columns[0].name.decode("utf-8") == "name" assert tag_schema1.columns[0].type.type == ttypes.PropertyType.STRING assert tag_schema1.columns[0].type.type_length == 0 - assert tag_schema2.columns[0].name.decode('utf-8') == 'name' + assert tag_schema2.columns[0].name.decode("utf-8") == "name" assert tag_schema2.columns[0].type.type == ttypes.PropertyType.STRING assert tag_schema2.columns[0].type.type_length == 0 # test not existed try: tag_item = self.meta_cache.get_tag_schema( - 'test_meta_cache1', 'tag_not_existed' + "test_meta_cache1", "tag_not_existed" ) assert False except Exception: assert True def test_get_edge_schema(self): - edge_schema1 = self.meta_cache.get_edge_schema('test_meta_cache1', 'edge11') - edge_schema2 = self.meta_cache.get_edge_schema('test_meta_cache2', 'edge22') - assert edge_schema1.columns[0].name.decode('utf-8') == 'name' + edge_schema1 = self.meta_cache.get_edge_schema("test_meta_cache1", "edge11") + edge_schema2 = self.meta_cache.get_edge_schema("test_meta_cache2", "edge22") + assert edge_schema1.columns[0].name.decode("utf-8") == "name" assert edge_schema1.columns[0].type.type == ttypes.PropertyType.STRING assert edge_schema1.columns[0].type.type_length == 0 - assert edge_schema2.columns[0].name.decode('utf-8') == 'name' + assert edge_schema2.columns[0].name.decode("utf-8") == "name" assert edge_schema2.columns[0].type.type == ttypes.PropertyType.STRING assert edge_schema2.columns[0].type.type_length == 0 # test not existed try: edge_item = self.meta_cache.get_edge_schema( - 'test_meta_cache1', 'edge_not_existed' + "test_meta_cache1", "edge_not_existed" ) assert False except Exception: assert True def test_get_part_leader(self): - address = self.meta_cache.get_part_leader('test_meta_cache1', 1) - assert address.host.find('172.28.2') == 0 + address = self.meta_cache.get_part_leader("test_meta_cache1", 1) + assert address.host.find("172.28.2") == 0 assert address.port == 9779 def test_get_part_leaders(self): - part_addresses = self.meta_cache.get_part_leaders('test_meta_cache1') + part_addresses = self.meta_cache.get_part_leaders("test_meta_cache1") parts = [part for part in part_addresses.keys()] assert len(parts) == 100 @@ -145,9 +139,9 @@ def test_get_part_leaders(self): for part in part_addresses.keys(): assert part_addresses[part].host in [ - '172.28.2.1', - '172.28.2.2', - '172.28.2.3', + "172.28.2.1", + "172.28.2.2", + "172.28.2.3", ] ports = [part_addresses[part].port for part in part_addresses.keys()] @@ -158,7 +152,7 @@ def test_get_all_storage_addrs(self): addresses = self.meta_cache.get_all_storage_addrs() assert len(addresses) == 3 hosts = [addr.host for addr in addresses] - expected_hosts = ['172.28.2.1', '172.28.2.2', '172.28.2.3'] + expected_hosts = ["172.28.2.1", "172.28.2.2", "172.28.2.3"] hosts = sorted(hosts) expected_hosts = sorted(expected_hosts) assert hosts == expected_hosts @@ -168,7 +162,7 @@ def test_get_all_storage_addrs(self): assert ports == expected_hosts def test_get_part_alloc(self): - part_alloc = self.meta_cache.get_part_alloc('test_meta_cache1') + part_alloc = self.meta_cache.get_part_alloc("test_meta_cache1") assert len(part_alloc) == 100 expected_parts = [i for i in range(1, 101)] @@ -176,7 +170,7 @@ def test_get_part_alloc(self): assert sorted(expected_parts) == sorted(parts) hosts = [addr.host for addr in part_alloc[1]] - expected_hosts = ['172.28.2.1', '172.28.2.2', '172.28.2.3'] + expected_hosts = ["172.28.2.1", "172.28.2.2", "172.28.2.3"] assert sorted(hosts) == sorted(expected_hosts) ports = [addr.port for addr in part_alloc[1]] diff --git a/tests/test_pool.py b/tests/test_pool.py index 332dbd8a..e61f2daf 100644 --- a/tests/test_pool.py +++ b/tests/test_pool.py @@ -6,35 +6,28 @@ # This source code is licensed under Apache 2.0 License. -import sys import os import threading import time -import pytest - -current_dir = os.path.dirname(os.path.abspath(__file__)) -root_dir = os.path.join(current_dir, '..') -sys.path.insert(0, root_dir) - from unittest import TestCase -from nebula3.gclient.net import ConnectionPool +import pytest from nebula3.Config import Config - from nebula3.Exception import ( - NotValidConnectionException, InValidHostname, IOErrorException, + NotValidConnectionException, ) +from nebula3.gclient.net import ConnectionPool class TestConnectionPool(TestCase): @classmethod def setup_class(self): self.addresses = list() - self.addresses.append(('127.0.0.1', 9669)) - self.addresses.append(('127.0.0.1', 9670)) + self.addresses.append(("127.0.0.1", 9669)) + self.addresses.append(("127.0.0.1", 9670)) self.configs = Config() self.configs.min_connection_pool_size = 2 self.configs.max_connection_pool_size = 4 @@ -46,32 +39,32 @@ def setup_class(self): def test_right_hostname(self): pool = ConnectionPool() - assert pool.init([('localhost', 9669)], Config()) + assert pool.init([("localhost", 9669)], Config()) def test_wrong_hostname(self): pool = ConnectionPool() try: - pool.init([('wrong_host', 9669)], Config()) + pool.init([("wrong_host", 9669)], Config()) assert False except InValidHostname: assert True def test_ping(self): - assert self.pool.ping(('127.0.0.1', 9669)) - assert self.pool.ping(('127.0.0.1', 5000)) is False + assert self.pool.ping(("127.0.0.1", 9669)) + assert self.pool.ping(("127.0.0.1", 5000)) is False def test_init_failed(self): # init succeeded pool1 = ConnectionPool() addresses = list() - addresses.append(('127.0.0.1', 9669)) - addresses.append(('127.0.0.1', 9670)) + addresses.append(("127.0.0.1", 9669)) + addresses.append(("127.0.0.1", 9670)) assert pool1.init(addresses, Config()) # init failed, connected failed pool2 = ConnectionPool() addresses = list() - addresses.append(('127.0.0.1', 3800)) + addresses.append(("127.0.0.1", 3800)) try: pool2.init(addresses, Config()) assert False @@ -82,7 +75,7 @@ def test_init_failed(self): try: pool3 = ConnectionPool() addresses = list() - addresses.append(('not_exist_hostname', 3800)) + addresses.append(("not_exist_hostname", 3800)) assert not pool3.init(addresses, Config()) except InValidHostname: assert True, "We expected get the exception" @@ -91,14 +84,14 @@ def test_get_session(self): # get session succeeded sessions = list() for num in range(0, self.configs.max_connection_pool_size): - session = self.pool.get_session('root', 'nebula') - resp = session.execute('SHOW SPACES') + session = self.pool.get_session("root", "nebula") + resp = session.execute("SHOW SPACES") assert resp.is_succeeded() sessions.append(session) # get session failed try: - self.pool.get_session('root', 'nebula') + self.pool.get_session("root", "nebula") except NotValidConnectionException: assert True @@ -112,8 +105,8 @@ def test_get_session(self): # test get session after release for num in range(0, self.configs.max_connection_pool_size - 1): - session = self.pool.get_session('root', 'nebula') - resp = session.execute('SHOW SPACES') + session = self.pool.get_session("root", "nebula") + resp = session.execute("SHOW SPACES") assert resp.is_succeeded() sessions.append(session) @@ -124,24 +117,24 @@ def test_get_session(self): assert self.pool.connects() == 3 def test_stop_close(self): - session = self.pool.get_session('root', 'nebula') + session = self.pool.get_session("root", "nebula") assert session is not None - resp = session.execute('SHOW SPACES') + resp = session.execute("SHOW SPACES") assert resp.is_succeeded() self.pool.close() try: - new_session = self.pool.get_session('root', 'nebula') + new_session = self.pool.get_session("root", "nebula") except NotValidConnectionException: assert True except Exception as e: assert False, "We don't expect reach here:{}".format(e) try: - session.execute('SHOW SPACES') + session.execute("SHOW SPACES") except IOErrorException: assert True - except Exception as e: - assert False, "We don't expect reach here:".format(e) + except Exception: + assert False, "We don't expect reach here:".format() @pytest.mark.skip(reason="the test data without nba") def test_timeout(self): @@ -149,26 +142,24 @@ def test_timeout(self): config.timeout = 1000 config.max_connection_pool_size = 1 pool = ConnectionPool() - assert pool.init([('127.0.0.1', 9669)], config) - session = pool.get_session('root', 'nebula') + assert pool.init([("127.0.0.1", 9669)], config) + session = pool.get_session("root", "nebula") try: - resp = session.execute( - 'USE nba;GO 1000 STEPS FROM \"Tim Duncan\" OVER like' - ) + resp = session.execute('USE nba;GO 1000 STEPS FROM "Tim Duncan" OVER like') assert False except IOErrorException as e: assert True assert str(e).find("Read timed out") session.release() try: - session = pool.get_session('root', 'nebula') - except IOErrorException as e: + session = pool.get_session("root", "nebula") + except IOErrorException: assert False def test_multi_thread(): # Test multi thread - addresses = [('127.0.0.1', 9669), ('127.0.0.1', 9670)] + addresses = [("127.0.0.1", 9669), ("127.0.0.1", 9670)] configs = Config() thread_num = 6 configs.max_connection_pool_size = thread_num @@ -182,23 +173,23 @@ def pool_multi_thread_test(): session = None global success_flag try: - session = pool.get_session('root', 'nebula') + session = pool.get_session("root", "nebula") if session is None: success_flag = False return - space_name = 'space_' + threading.current_thread().getName() + space_name = "space_" + threading.current_thread().getName() - session.execute('DROP SPACE IF EXISTS %s' % space_name) + session.execute("DROP SPACE IF EXISTS %s" % space_name) resp = session.execute( - 'CREATE SPACE IF NOT EXISTS %s(vid_type=FIXED_STRING(8))' % space_name + "CREATE SPACE IF NOT EXISTS %s(vid_type=FIXED_STRING(8))" % space_name ) if not resp.is_succeeded(): - raise RuntimeError('CREATE SPACE failed: {}'.format(resp.error_msg())) + raise RuntimeError("CREATE SPACE failed: {}".format(resp.error_msg())) time.sleep(3) - resp = session.execute('USE %s' % space_name) + resp = session.execute("USE %s" % space_name) if not resp.is_succeeded(): - raise RuntimeError('USE SPACE failed:{}'.format(resp.error_msg())) + raise RuntimeError("USE SPACE failed:{}".format(resp.error_msg())) except Exception as x: print(x) @@ -211,7 +202,7 @@ def pool_multi_thread_test(): threads = [] for num in range(0, thread_num): thread = threading.Thread( - target=pool_multi_thread_test, name='test_pool_thread' + str(num) + target=pool_multi_thread_test, name="test_pool_thread" + str(num) ) thread.start() threads.append(thread) @@ -225,7 +216,7 @@ def pool_multi_thread_test(): def test_session_context_multi_thread(): # Test multi thread - addresses = [('127.0.0.1', 9669), ('127.0.0.1', 9670)] + addresses = [("127.0.0.1", 9669), ("127.0.0.1", 9670)] configs = Config() thread_num = 50 configs.max_connection_pool_size = thread_num @@ -239,26 +230,26 @@ def pool_session_context_multi_thread_test(): session = None global success_flag try: - with pool.session_context('root', 'nebula') as session: + with pool.session_context("root", "nebula") as session: if session is None: success_flag = False return - space_name = 'space_' + threading.current_thread().getName() + space_name = "space_" + threading.current_thread().getName() - session.execute('DROP SPACE IF EXISTS %s' % space_name) + session.execute("DROP SPACE IF EXISTS %s" % space_name) resp = session.execute( - 'CREATE SPACE IF NOT EXISTS %s(vid_type=FIXED_STRING(8))' + "CREATE SPACE IF NOT EXISTS %s(vid_type=FIXED_STRING(8))" % space_name ) if not resp.is_succeeded(): raise RuntimeError( - 'CREATE SPACE failed: {}'.format(resp.error_msg()) + "CREATE SPACE failed: {}".format(resp.error_msg()) ) time.sleep(3) - resp = session.execute('USE %s' % space_name) + resp = session.execute("USE %s" % space_name) if not resp.is_succeeded(): - raise RuntimeError('USE SPACE failed:{}'.format(resp.error_msg())) + raise RuntimeError("USE SPACE failed:{}".format(resp.error_msg())) except Exception as x: print(x) @@ -269,7 +260,7 @@ def pool_session_context_multi_thread_test(): for num in range(0, thread_num): thread = threading.Thread( target=pool_session_context_multi_thread_test, - name='test_session_context_thread' + str(num), + name="test_session_context_thread" + str(num), ) thread.start() threads.append(thread) @@ -282,7 +273,7 @@ def pool_session_context_multi_thread_test(): def test_remove_invalid_connection(): - addresses = [('127.0.0.1', 9669), ('127.0.0.1', 9670), ('127.0.0.1', 9671)] + addresses = [("127.0.0.1", 9669), ("127.0.0.1", 9670), ("127.0.0.1", 9671)] configs = Config() configs.min_connection_pool_size = 30 configs.max_connection_pool_size = 45 @@ -292,7 +283,7 @@ def test_remove_invalid_connection(): assert pool.init(addresses, configs) # turn down one server('127.0.0.1', 9669) so the connection to it is invalid - os.system('docker stop tests_graphd0_1') + os.system("docker stop tests_graphd0_1") time.sleep(3) # get connection from the pool, we should be able to still get 30 connections even though one server is down @@ -311,5 +302,5 @@ def test_remove_invalid_connection(): assert len(pool._connections[addresses[2]]) == 15 finally: - os.system('docker start tests_graphd0_1') + os.system("docker start tests_graphd0_1") time.sleep(3) diff --git a/tests/test_session.py b/tests/test_session.py index 377b3b9c..4bf0942a 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -6,29 +6,24 @@ # This source code is licensed under Apache 2.0 License. -import sys import os import time - -current_dir = os.path.dirname(os.path.abspath(__file__)) -root_dir = os.path.join(current_dir, '..') -sys.path.insert(0, root_dir) - from unittest import TestCase -from nebula3.gclient.net import ConnectionPool + from nebula3.Config import Config +from nebula3.gclient.net import ConnectionPool class TestSession(TestCase): @classmethod def setup_class(self): - self.user_name = 'root' - self.password = 'nebula' + self.user_name = "root" + self.password = "nebula" self.configs = Config() self.configs.max_connection_pool_size = 6 self.pool = ConnectionPool() assert self.pool.init( - [('127.0.0.1', 9669), ('127.0.0.1', 9670), ('127.0.0.1', 9671)], + [("127.0.0.1", 9669), ("127.0.0.1", 9670), ("127.0.0.1", 9671)], self.configs, ) assert self.pool.connects() == 0 @@ -36,7 +31,7 @@ def setup_class(self): def test_1_release_by_del(self): def get_local_session(pool): - session = pool.get_session('root', 'nebula') + session = pool.get_session("root", "nebula") assert pool.in_used_connects() == 1 get_local_session(self.pool) @@ -44,37 +39,37 @@ def get_local_session(pool): def test_2_reconnect(self): try: - session = self.pool.get_session('root', 'nebula') + session = self.pool.get_session("root", "nebula") time.sleep(2) # wait for the session space info to be updated to meta service resp = session.execute( - 'CREATE SPACE IF NOT EXISTS test_session(vid_type=FIXED_STRING(8)); USE test_session;' + "CREATE SPACE IF NOT EXISTS test_session(vid_type=FIXED_STRING(8)); USE test_session;" ) assert resp.is_succeeded(), resp.error_msg() time.sleep(10) for i in range(0, 5): if i == 3: - os.system('docker stop tests_graphd0_1') - os.system('docker stop tests_graphd1_1') + os.system("docker stop tests_graphd0_1") + os.system("docker stop tests_graphd1_1") time.sleep(3) - resp = session.execute('SHOW SESSIONS') + resp = session.execute("SHOW SESSIONS") assert resp.is_succeeded(), resp.error_msg() - assert resp.space_name() == 'test_session' + assert resp.space_name() == "test_session" time.sleep(2) session.release() - new_session = self.pool.get_session('root', 'nebula') - new_session.execute('SHOW SPACES') + new_session = self.pool.get_session("root", "nebula") + new_session.execute("SHOW SPACES") except Exception as e: assert False, e finally: - os.system('docker start tests_graphd0_1') - os.system('docker start tests_graphd1_1') + os.system("docker start tests_graphd0_1") + os.system("docker start tests_graphd1_1") time.sleep(2) def test_3_session_context(self): in_used_connects = self.pool.in_used_connects() - with self.pool.session_context('root', 'nebula') as session: + with self.pool.session_context("root", "nebula") as session: assert self.pool.in_used_connects() == in_used_connects + 1 assert self.pool.in_used_connects() == in_used_connects @@ -84,13 +79,13 @@ def test_4_timeout(self): configs.timeout = 100 configs.max_connection_pool_size = 1 pool = ConnectionPool() - assert pool.init([('127.0.0.1', 9669)], configs) + assert pool.init([("127.0.0.1", 9669)], configs) session = pool.get_session(self.user_name, self.password) - ngql = '' + ngql = "" for n in range(0, 500): - ngql = ngql + 'show hosts;' + ngql = ngql + "show hosts;" session.execute(ngql) - assert False, 'expect to get exception' + assert False, "expect to get exception" except Exception as ex: - assert str(ex).find('timed out') > 0 + assert str(ex).find("timed out") > 0 assert True, ex diff --git a/tests/test_session_pool.py b/tests/test_session_pool.py index e15b5f5f..f508dc3a 100644 --- a/tests/test_session_pool.py +++ b/tests/test_session_pool.py @@ -6,60 +6,50 @@ # This source code is licensed under Apache 2.0 License. -from distutils.command.config import config import json -import sys -import os import threading import time - -current_dir = os.path.dirname(os.path.abspath(__file__)) -root_dir = os.path.join(current_dir, '..') -sys.path.insert(0, root_dir) - from unittest import TestCase + from nebula3.common.ttypes import ErrorCode -from nebula3.gclient.net.SessionPool import SessionPool -from nebula3.gclient.net import Connection from nebula3.Config import SessionPoolConfig - from nebula3.Exception import ( - NoValidSessionException, InValidHostname, - IOErrorException, ) +from nebula3.gclient.net import Connection +from nebula3.gclient.net.SessionPool import SessionPool # ports for test test_port = 9669 test_port2 = 9670 -def prepare_space(space_name='session_pool_test'): +def prepare_space(space_name="session_pool_test"): # prepare space conn = Connection() - conn.open('127.0.0.1', test_port, 1000) - auth_result = conn.authenticate('root', 'nebula') + conn.open("127.0.0.1", test_port, 1000) + auth_result = conn.authenticate("root", "nebula") assert auth_result.get_session_id() != 0 resp = conn.execute( auth_result._session_id, - 'CREATE SPACE IF NOT EXISTS {}(partition_num=32, replica_factor=1, vid_type = FIXED_STRING(30))'.format( + "CREATE SPACE IF NOT EXISTS {}(partition_num=32, replica_factor=1, vid_type = FIXED_STRING(30))".format( space_name ), ) assert resp.error_code == ErrorCode.SUCCEEDED -def drop_space(space_name='session_pool_test'): +def drop_space(space_name="session_pool_test"): # drop space conn = Connection() - conn.open('127.0.0.1', test_port, 1000) - auth_result = conn.authenticate('root', 'nebula') + conn.open("127.0.0.1", test_port, 1000) + auth_result = conn.authenticate("root", "nebula") assert auth_result.get_session_id() != 0 # drop space resp = conn.execute( auth_result._session_id, - 'DROP SPACE IF EXISTS {}'.format(space_name), + "DROP SPACE IF EXISTS {}".format(space_name), ) assert resp.error_code == ErrorCode.SUCCEEDED @@ -68,8 +58,8 @@ class TestSessionPoolBasic(TestCase): @classmethod def setup_class(self): self.addresses = list() - self.addresses.append(('127.0.0.1', test_port)) - self.addresses.append(('127.0.0.1', test_port2)) + self.addresses.append(("127.0.0.1", test_port)) + self.addresses.append(("127.0.0.1", test_port2)) self.configs = SessionPoolConfig() self.configs.min_size = 2 self.configs.max_size = 4 @@ -77,31 +67,31 @@ def setup_class(self): self.configs.interval_check = 2 # prepare space - prepare_space('session_pool_test') - prepare_space('session_pool_test_2') + prepare_space("session_pool_test") + prepare_space("session_pool_test_2") # insert data need to sleep after create schema time.sleep(10) self.session_pool = SessionPool( - 'root', 'nebula', 'session_pool_test', self.addresses + "root", "nebula", "session_pool_test", self.addresses ) assert self.session_pool.init(self.configs) def tearDown_Class(self): - drop_space('session_pool_test') - drop_space('session_pool_test_2') + drop_space("session_pool_test") + drop_space("session_pool_test_2") def test_pool_init(self): # basic session_pool = SessionPool( - 'root', 'nebula', 'session_pool_test', self.addresses + "root", "nebula", "session_pool_test", self.addresses ) assert session_pool.init(self.configs) # handle wrong service port pool = SessionPool( - 'root', 'nebula', 'session_pool_test', [('127.0.0.1', 3800)] + "root", "nebula", "session_pool_test", [("127.0.0.1", 3800)] ) # wrong port try: pool.init(self.configs) @@ -112,7 +102,7 @@ def test_pool_init(self): # handle invalid hostname try: session_pool = SessionPool( - 'root', 'nebula', 'session_pool_test', [('wrong_host', test_port)] + "root", "nebula", "session_pool_test", [("wrong_host", test_port)] ) session_pool.init(self.configs) assert False @@ -121,14 +111,14 @@ def test_pool_init(self): def test_ping(self): assert self.session_pool.ping(self.addresses[0]) - assert self.session_pool.ping(('127.0.0.1', 5000)) is False + assert self.session_pool.ping(("127.0.0.1", 5000)) is False def test_execute(self): - resp = self.session_pool.execute('SHOW HOSTS') + resp = self.session_pool.execute("SHOW HOSTS") assert resp.is_succeeded() def test_execute_json(self): - resp = self.session_pool.execute_json('SHOW HOSTS') + resp = self.session_pool.execute_json("SHOW HOSTS") json_obj = json.loads(resp) # Get errorcode resp_error_code = json_obj["errors"][0]["code"] @@ -138,20 +128,20 @@ def test_switch_space(self): # This test is used to test if the space bond to session is the same as the space in the session pool config after executing # a query contains `USE ` statement. session_pool = SessionPool( - 'root', 'nebula', 'session_pool_test', self.addresses + "root", "nebula", "session_pool_test", self.addresses ) configs = SessionPoolConfig() configs.min_size = 1 configs.max_size = 1 assert session_pool.init(configs) - resp = session_pool.execute('USE session_pool_test_2; SHOW HOSTS;') + resp = session_pool.execute("USE session_pool_test_2; SHOW HOSTS;") assert resp.is_succeeded() # The space in the session pool config should be the same as the space in the session. - resp = session_pool.execute('SHOW HOSTS;') + resp = session_pool.execute("SHOW HOSTS;") assert resp.is_succeeded() - assert resp.space_name() == 'session_pool_test' + assert resp.space_name() == "session_pool_test" def test_session_pool_multi_thread(): @@ -159,14 +149,14 @@ def test_session_pool_multi_thread(): prepare_space() # Test multi thread - addresses = [('127.0.0.1', test_port), ('127.0.0.1', test_port2)] + addresses = [("127.0.0.1", test_port), ("127.0.0.1", test_port2)] configs = SessionPoolConfig() configs.min_size = 2 configs.max_size = 4 configs.idle_time = 2000 configs.interval_check = 2 - session_pool = SessionPool('root', 'nebula', 'session_pool_test', addresses) + session_pool = SessionPool("root", "nebula", "session_pool_test", addresses) assert session_pool.init(configs) global success_flag @@ -175,10 +165,10 @@ def test_session_pool_multi_thread(): def main_test(): global success_flag try: - resp = session_pool.execute('SHOW HOSTS') + resp = session_pool.execute("SHOW HOSTS") if not resp.is_succeeded(): raise RuntimeError( - 'Failed to execute the query in thread {} : {}'.format( + "Failed to execute the query in thread {} : {}".format( threading.current_thread().getName(), resp.error_msg() ) ) @@ -188,10 +178,10 @@ def main_test(): success_flag = False return - thread1 = threading.Thread(target=main_test, name='thread1') - thread2 = threading.Thread(target=main_test, name='thread2') - thread3 = threading.Thread(target=main_test, name='thread3') - thread4 = threading.Thread(target=main_test, name='thread4') + thread1 = threading.Thread(target=main_test, name="thread1") + thread2 = threading.Thread(target=main_test, name="thread2") + thread3 = threading.Thread(target=main_test, name="thread3") + thread4 = threading.Thread(target=main_test, name="thread4") thread1.start() thread2.start() diff --git a/tests/test_ssl_connection.py b/tests/test_ssl_connection.py index ea443c86..73b9dc5f 100644 --- a/tests/test_ssl_connection.py +++ b/tests/test_ssl_connection.py @@ -5,38 +5,36 @@ # # This source code is licensed under Apache 2.0 License. -import sys import os -import time import ssl -import pytest +import time +from unittest import TestCase -current_dir = os.path.dirname(os.path.abspath(__file__)) -root_dir = os.path.join(current_dir, '..') -sys.path.insert(0, root_dir) +import pytest -from unittest import TestCase -from nebula3.Exception import IOErrorException from nebula3.common import ttypes -from nebula3.gclient.net import Connection from nebula3.Config import SSL_config +from nebula3.Exception import IOErrorException +from nebula3.gclient.net import Connection + +current_dir = os.path.dirname(os.path.abspath(__file__)) # set SSL config ssl_config = SSL_config() ssl_config.cert_reqs = ssl.CERT_OPTIONAL -ssl_config.ca_certs = os.path.join(current_dir, 'secrets/root.crt') -ssl_config.keyfile = os.path.join(current_dir, 'secrets/client.key') -ssl_config.certfile = os.path.join(current_dir, 'secrets/client.crt') +ssl_config.ca_certs = os.path.join(current_dir, "secrets/root.crt") +ssl_config.keyfile = os.path.join(current_dir, "secrets/client.key") +ssl_config.certfile = os.path.join(current_dir, "secrets/client.crt") # self signed SSL config ssl_selfs_signed_config = SSL_config() ssl_selfs_signed_config.cert_reqs = ssl.CERT_OPTIONAL ssl_selfs_signed_config.cert_reqs = ssl.CERT_OPTIONAL -ssl_selfs_signed_config.ca_certs = os.path.join(current_dir, 'secrets/root.crt') -ssl_selfs_signed_config.keyfile = os.path.join(current_dir, 'secrets/client.key') -ssl_selfs_signed_config.certfile = os.path.join(current_dir, 'secrets/client.crt') +ssl_selfs_signed_config.ca_certs = os.path.join(current_dir, "secrets/root.crt") +ssl_selfs_signed_config.keyfile = os.path.join(current_dir, "secrets/client.key") +ssl_selfs_signed_config.certfile = os.path.join(current_dir, "secrets/client.crt") -host = '127.0.0.1' +host = "127.0.0.1" port = 9669 @@ -46,7 +44,7 @@ def test_create(self): try: conn = Connection() conn.open_SSL(host, port, 1000, ssl_config) - auth_result = conn.authenticate('root', 'nebula') + auth_result = conn.authenticate("root", "nebula") assert auth_result.get_session_id() != 0 conn.close() except Exception as ex: @@ -56,15 +54,15 @@ def test_release(self): try: conn = Connection() conn.open_SSL(host, port, 1000, ssl_config) - auth_result = conn.authenticate('root', 'nebula') + auth_result = conn.authenticate("root", "nebula") session_id = auth_result.get_session_id() assert session_id != 0 - resp = conn.execute(session_id, 'SHOW SPACES') + resp = conn.execute(session_id, "SHOW SPACES") assert resp.error_code == ttypes.ErrorCode.SUCCEEDED, resp.error_msg conn.signout(session_id) # the session delete later time.sleep(12) - resp = conn.execute(session_id, 'SHOW SPACES') + resp = conn.execute(session_id, "SHOW SPACES") assert resp.error_code != ttypes.ErrorCode.SUCCEEDED conn.close() except Exception as ex: @@ -73,11 +71,11 @@ def test_release(self): def test_close(self): conn = Connection() conn.open_SSL(host, port, 1000, ssl_config) - auth_result = conn.authenticate('root', 'nebula') + auth_result = conn.authenticate("root", "nebula") assert auth_result.get_session_id() != 0 conn.close() try: - conn.authenticate('root', 'nebula') + conn.authenticate("root", "nebula") except IOErrorException: assert True @@ -88,7 +86,7 @@ def test_create_self_signed(self): try: conn = Connection() conn.open_SSL(host, port, 1000, ssl_selfs_signed_config) - auth_result = conn.authenticate('root', 'nebula') + auth_result = conn.authenticate("root", "nebula") assert auth_result.get_session_id() != 0 conn.close() except Exception as ex: @@ -98,15 +96,15 @@ def test_release_self_signed(self): try: conn = Connection() conn.open_SSL(host, port, 1000, ssl_selfs_signed_config) - auth_result = conn.authenticate('root', 'nebula') + auth_result = conn.authenticate("root", "nebula") session_id = auth_result.get_session_id() assert session_id != 0 - resp = conn.execute(session_id, 'SHOW SPACES') + resp = conn.execute(session_id, "SHOW SPACES") assert resp.error_code == ttypes.ErrorCode.SUCCEEDED, resp.error_msg conn.signout(session_id) # the session delete later time.sleep(12) - resp = conn.execute(session_id, 'SHOW SPACES') + resp = conn.execute(session_id, "SHOW SPACES") assert resp.error_code != ttypes.ErrorCode.SUCCEEDED conn.close() except Exception as ex: @@ -115,10 +113,10 @@ def test_release_self_signed(self): def test_close_self_signed(self): conn = Connection() conn.open_SSL(host, port, 1000, ssl_selfs_signed_config) - auth_result = conn.authenticate('root', 'nebula') + auth_result = conn.authenticate("root", "nebula") assert auth_result.get_session_id() != 0 conn.close() try: - conn.authenticate('root', 'nebula') + conn.authenticate("root", "nebula") except IOErrorException: assert True diff --git a/tests/test_ssl_pool.py b/tests/test_ssl_pool.py index c532ef8b..52cc7b54 100644 --- a/tests/test_ssl_pool.py +++ b/tests/test_ssl_pool.py @@ -4,20 +4,17 @@ # Copyright (c) 2021 vesoft inc. All rights reserved. # # This source code is licensed under Apache 2.0 License. -import sys +import copy import os import ssl -import copy -import pytest - -current_dir = os.path.dirname(os.path.abspath(__file__)) -root_dir = os.path.join(current_dir, '..') -sys.path.insert(0, root_dir) - from unittest import TestCase -from nebula3.gclient.net import ConnectionPool +import pytest + from nebula3.Config import Config, SSL_config +from nebula3.gclient.net import ConnectionPool + +current_dir = os.path.dirname(os.path.abspath(__file__)) @pytest.mark.SSL @@ -25,7 +22,7 @@ class TestConnectionPool(TestCase): @classmethod def setup_class(self): self.addresses = list() - self.addresses.append(('127.0.0.1', 9669)) + self.addresses.append(("127.0.0.1", 9669)) self.configs = Config() self.configs.min_connection_pool_size = 2 self.configs.max_connection_pool_size = 4 @@ -35,20 +32,20 @@ def setup_class(self): # set SSL config self.ssl_config = SSL_config() self.ssl_config.cert_reqs = ssl.CERT_OPTIONAL - self.ssl_config.ca_certs = os.path.join(current_dir, 'secrets/root.crt') - self.ssl_config.keyfile = os.path.join(current_dir, 'secrets/client.key') - self.ssl_config.certfile = os.path.join(current_dir, 'secrets/client.crt') + self.ssl_config.ca_certs = os.path.join(current_dir, "secrets/root.crt") + self.ssl_config.keyfile = os.path.join(current_dir, "secrets/client.key") + self.ssl_config.certfile = os.path.join(current_dir, "secrets/client.crt") # self signed SSL config self.ssl_selfs_signed_config = SSL_config() self.ssl_selfs_signed_config.cert_reqs = ssl.CERT_OPTIONAL self.ssl_selfs_signed_config.ca_certs = os.path.join( - current_dir, 'secrets/root.crt' + current_dir, "secrets/root.crt" ) self.ssl_selfs_signed_config.keyfile = os.path.join( - current_dir, 'secrets/client.key' + current_dir, "secrets/client.key" ) self.ssl_selfs_signed_config.certfile = os.path.join( - current_dir, 'secrets/client.crt' + current_dir, "secrets/client.crt" ) def test_ssl_with_ca(self):