This is an automated email from the ASF dual-hosted git repository.

ming pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph-ai.git


The following commit(s) were added to refs/heads/main by this push:
     new 1466986  feat(client): add variables api and test (#24)
1466986 is described below

commit 14669867224d284348c205530386f3d049019d87
Author: Liu Xiao <[email protected]>
AuthorDate: Thu Oct 26 14:19:40 2023 +0800

    feat(client): add variables api and test (#24)
    
    * feat: add variables api
    
    * revert example port
    
    * update
    
    * fix
    
    * fix
    
    * format
    
    * add example
    
    * fix
    
    * fix
    
    * clear data
    
    * fix
    
    ---------
    
    Co-authored-by: Simon Cheung <[email protected]>
---
 .github/workflows/hugegraph-python-client.yml      |  39 +++++++
 .github/workflows/pylint.yml                       |   2 +-
 .../example/{test.py => hugegraph_example.py}      |   4 +-
 hugegraph-python-client/requirements.txt           |   2 +-
 .../src/pyhugegraph/api/gremlin.py                 | 105 ++++++++++--------
 .../src/pyhugegraph/api/variable.py                |  90 +++++++++++++++
 hugegraph-python-client/src/pyhugegraph/client.py  | 122 +++++++++++----------
 .../src/pyhugegraph/structure/gremlin_data.py      |  73 ++++++++++++
 hugegraph-python-client/src/tests/__init__.py      |  16 +++
 hugegraph-python-client/src/tests/api/__init__.py  |  16 +++
 .../src/tests/api/test_gremlin.py                  |  92 ++++++++++++++++
 .../src/tests/api/test_variable.py                 |  82 ++++++++++++++
 hugegraph-python-client/src/tests/client_utils.py  | 101 +++++++++++++++++
 13 files changed, 636 insertions(+), 108 deletions(-)

diff --git a/.github/workflows/hugegraph-python-client.yml 
b/.github/workflows/hugegraph-python-client.yml
new file mode 100644
index 0000000..450ebf5
--- /dev/null
+++ b/.github/workflows/hugegraph-python-client.yml
@@ -0,0 +1,39 @@
+name: HG-Python-Client CI
+
+on:
+  push:
+    branches:
+      - 'release-*'
+  pull_request:
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        python-version: ["3.8", "3.9", "3.10", "3.11"]
+    steps:
+    - uses: actions/checkout@v3
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v4
+      with:
+        python-version: ${{ matrix.python-version }}
+        cache: 'pip'
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        pip install pytest
+        pip install -r ./hugegraph-python-client/requirements.txt
+    - name: Prepare HugeGraph Server Environment
+      run: |
+        docker run -d --name=graph -p 8080:8080 hugegraph/hugegraph
+        sleep 20
+    - name: Test example
+      run: |
+        export PYTHONPATH=$(pwd)/hugegraph-python-client/src
+        echo ${PYTHONPATH}
+        python hugegraph-python-client/example/hugegraph_example.py
+    - name: Test with pytest
+      run: |
+        pytest
+      working-directory: hugegraph-python-client
diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml
index ccb4613..7467c4f 100644
--- a/.github/workflows/pylint.yml
+++ b/.github/workflows/pylint.yml
@@ -21,7 +21,7 @@ jobs:
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
-        pip install pylint
+        pip install pylint pytest
         pip install -r ./hugegraph-llm/requirements.txt 
         pip install -r ./hugegraph-python-client/requirements.txt
     - name: Analysing the code with pylint
diff --git a/hugegraph-python-client/example/test.py 
b/hugegraph-python-client/example/hugegraph_example.py
similarity index 96%
rename from hugegraph-python-client/example/test.py
rename to hugegraph-python-client/example/hugegraph_example.py
index 5162444..27d0246 100644
--- a/hugegraph-python-client/example/test.py
+++ b/hugegraph-python-client/example/hugegraph_example.py
@@ -18,7 +18,7 @@
 from pyhugegraph.client import PyHugeClient
 
 if __name__ == "__main__":
-    client = PyHugeClient("127.0.0.1", "8080", user="admin", pwd="admin", 
graph="test")
+    client = PyHugeClient("127.0.0.1", "8080", user="admin", pwd="admin", 
graph="hugegraph")
 
     """schema"""
     schema = client.schema()
@@ -52,7 +52,7 @@ if __name__ == "__main__":
     g.addEdge("ActedIn", p2.id, m2.id, {})
 
     # update property
-    g.eliminateVertex("vertex_id", {"property_key": "property_value"})
+    # g.eliminateVertex("vertex_id", {"property_key": "property_value"})
 
     print(g.getVertexById(p1.id).label)
     # g.removeVertexById("12:Al Pacino")
diff --git a/hugegraph-python-client/requirements.txt 
b/hugegraph-python-client/requirements.txt
index 6d154a0..469bab3 100644
--- a/hugegraph-python-client/requirements.txt
+++ b/hugegraph-python-client/requirements.txt
@@ -1,4 +1,4 @@
 decorator==5.1.1
-Requests==2.31.0
+requests==2.31.0
 setuptools==67.6.1
 urllib3==2.0.7
diff --git a/hugegraph-python-client/src/pyhugegraph/api/gremlin.py 
b/hugegraph-python-client/src/pyhugegraph/api/gremlin.py
index 97b63cb..fcffd98 100644
--- a/hugegraph-python-client/src/pyhugegraph/api/gremlin.py
+++ b/hugegraph-python-client/src/pyhugegraph/api/gremlin.py
@@ -1,47 +1,58 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-import json
-import re
-
-from pyhugegraph.api.common import HugeParamsBase
-from pyhugegraph.structure.response_data import ResponseData
-from pyhugegraph.utils.exceptions import NotFoundError
-from pyhugegraph.utils.huge_requests import HugeSession
-from pyhugegraph.utils.util import check_if_success
-
-
-class GremlinManager(HugeParamsBase):
-    def __init__(self, graph_instance):
-        super().__init__(graph_instance)
-        self.session = self.set_session(HugeSession.new_session())
-
-    def set_session(self, session):
-        self.session = session
-        return session
-
-    def close(self):
-        if self.session:
-            self.session.close()
-
-    def exec(self, gremlin):
-        gremlin = re.sub("^g", self._graph_name + ".traversal()", gremlin)
-        url = f"{self._host}/gremlin?gremlin={gremlin}"
-        response = self.session.get(url, auth=self._auth, 
headers=self._headers)
-        error = NotFoundError(f"Gremlin can't get results: {response.content}")
-        if check_if_success(response, error):
-            return ResponseData(json.loads(response.content)).result
-        return ""
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import json
+
+from pyhugegraph.api.common import HugeParamsBase
+from pyhugegraph.structure.gremlin_data import GremlinData
+from pyhugegraph.structure.response_data import ResponseData
+from pyhugegraph.utils.exceptions import NotFoundError
+from pyhugegraph.utils.huge_requests import HugeSession
+from pyhugegraph.utils.util import check_if_success
+
+
+class GremlinManager(HugeParamsBase):
+    def __init__(self, graph_instance):
+        super().__init__(graph_instance)
+        self.session = self.set_session(HugeSession.new_session())
+
+    def set_session(self, session):
+        self.session = session
+        return session
+
+    def close(self):
+        if self.session:
+            self.session.close()
+
+    def exec(self, gremlin):
+        url = f"{self._host}/gremlin"
+        gremlin_data = GremlinData(gremlin)
+        gremlin_data.aliases = {
+            'graph': self._graph_name,
+            'g': '__g_' + self._graph_name
+        }
+        response = self.session.post(
+            url,
+            data=gremlin_data.to_json(),
+            auth=self._auth,
+            headers=self._headers,
+            timeout=self._timeout
+        )
+        error = NotFoundError(f"Gremlin can't get results: {response.content}")
+        if check_if_success(response, error):
+            return ResponseData(json.loads(response.content)).result
+        return ""
diff --git a/hugegraph-python-client/src/pyhugegraph/api/variable.py 
b/hugegraph-python-client/src/pyhugegraph/api/variable.py
new file mode 100644
index 0000000..16abe61
--- /dev/null
+++ b/hugegraph-python-client/src/pyhugegraph/api/variable.py
@@ -0,0 +1,90 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import json
+
+from pyhugegraph.api.common import HugeParamsBase
+from pyhugegraph.utils.exceptions import NotFoundError
+from pyhugegraph.utils.huge_requests import HugeSession
+from pyhugegraph.utils.util import check_if_success
+
+
+class VariableManager(HugeParamsBase):
+
+    def __init__(self, graph_instance):
+        super().__init__(graph_instance)
+        self.session = self.set_session(HugeSession.new_session())
+
+    def set_session(self, session):
+        self.session = session
+        return session
+
+    def close(self):
+        if self.session:
+            self.session.close()
+
+    def set(self, key, value):
+        url = f'{self._host}/graphs/{self._graph_name}/variables/{key}'
+        data = {'data': value}
+
+        response = self.session.put(
+            url,
+            data=json.dumps(data),
+            auth=self._auth,
+            headers=self._headers,
+            timeout=self._timeout,
+        )
+        if check_if_success(response, NotFoundError(response.content)):
+            return response.json()
+        return {}
+
+    def get(self, key):
+        url = f'{self._host}/graphs/{self._graph_name}/variables/{key}'
+
+        response = self.session.get(
+            url,
+            auth=self._auth,
+            headers=self._headers,
+            timeout=self._timeout
+        )
+        if check_if_success(response, NotFoundError(response.content)):
+            return response.json()
+        return {}
+
+    def all(self):
+        url = f'{self._host}/graphs/{self._graph_name}/variables'
+
+        response = self.session.get(
+            url,
+            auth=self._auth,
+            headers=self._headers,
+            timeout=self._timeout
+        )
+        if check_if_success(response, NotFoundError(response.content)):
+            return response.json()
+        return {}
+
+    def remove(self, key):
+        url = f'{self._host}/graphs/{self._graph_name}/variables/{key}'
+
+        response = self.session.delete(
+            url,
+            auth=self._auth,
+            headers=self._headers,
+            timeout=self._timeout
+        )
+        check_if_success(response, NotFoundError(response.content))
diff --git a/hugegraph-python-client/src/pyhugegraph/client.py 
b/hugegraph-python-client/src/pyhugegraph/client.py
index e12b73d..3972af0 100644
--- a/hugegraph-python-client/src/pyhugegraph/client.py
+++ b/hugegraph-python-client/src/pyhugegraph/client.py
@@ -1,57 +1,65 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-from pyhugegraph.api.common import HugeParamsBase
-from pyhugegraph.api.graph import GraphManager
-from pyhugegraph.api.graphs import GraphsManager
-from pyhugegraph.api.gremlin import GremlinManager
-from pyhugegraph.api.schema import SchemaManager
-from pyhugegraph.structure.graph_instance import GraphInstance
-
-
-class PyHugeClient(HugeParamsBase):
-    def __init__(self, ip, port, graph, user, pwd, timeout=10):
-        self._graph_instance = GraphInstance(ip, port, graph, user, pwd, 
timeout)
-        super().__init__(self._graph_instance)
-        self._schema = None
-        self._graph = None
-        self._graphs = None
-        self._gremlin = None
-
-    def schema(self):
-        if self._schema:
-            return self._schema
-        self._schema = SchemaManager(self._graph_instance)
-        return self._schema
-
-    def gremlin(self):
-        if self._gremlin:
-            return self._gremlin
-        self._gremlin = GremlinManager(self._graph_instance)
-        return self._gremlin
-
-    def graph(self):
-        if self._graph:
-            return self._graph
-        self._graph = GraphManager(self._graph_instance)
-        return self._graph
-
-    def graphs(self):
-        if self._graphs:
-            return self._graphs
-        self._graphs = GraphsManager(self._graph_instance)
-        return self._graphs
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from pyhugegraph.api.common import HugeParamsBase
+from pyhugegraph.api.graph import GraphManager
+from pyhugegraph.api.graphs import GraphsManager
+from pyhugegraph.api.gremlin import GremlinManager
+from pyhugegraph.api.schema import SchemaManager
+from pyhugegraph.api.variable import VariableManager
+from pyhugegraph.structure.graph_instance import GraphInstance
+
+
+class PyHugeClient(HugeParamsBase):
+    def __init__(self, ip, port, graph, user, pwd, timeout=10):
+        self._graph_instance = GraphInstance(ip, port, graph, user, pwd, 
timeout)
+        super().__init__(self._graph_instance)
+        self._schema = None
+        self._graph = None
+        self._graphs = None
+        self._gremlin = None
+        self._variable = None
+
+    def schema(self):
+        if self._schema:
+            return self._schema
+        self._schema = SchemaManager(self._graph_instance)
+        return self._schema
+
+    def gremlin(self):
+        if self._gremlin:
+            return self._gremlin
+        self._gremlin = GremlinManager(self._graph_instance)
+        return self._gremlin
+
+    def graph(self):
+        if self._graph:
+            return self._graph
+        self._graph = GraphManager(self._graph_instance)
+        return self._graph
+
+    def graphs(self):
+        if self._graphs:
+            return self._graphs
+        self._graphs = GraphsManager(self._graph_instance)
+        return self._graphs
+
+    def variable(self):
+        if self._variable:
+            return self._variable
+        self._variable = VariableManager(self._graph_instance)
+        return self._variable
diff --git a/hugegraph-python-client/src/pyhugegraph/structure/gremlin_data.py 
b/hugegraph-python-client/src/pyhugegraph/structure/gremlin_data.py
new file mode 100644
index 0000000..9440b84
--- /dev/null
+++ b/hugegraph-python-client/src/pyhugegraph/structure/gremlin_data.py
@@ -0,0 +1,73 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import json
+
+
+class GremlinData:
+
+    def __init__(self, gremlin):
+        self.__gremlin = gremlin
+        self.__bindings = {}
+        self.__language = "gremlin-groovy"
+        self.__aliases = {}
+
+    @property
+    def gremlin(self):
+        return self.__gremlin
+
+    @gremlin.setter
+    def gremlin(self, _gremlin):
+        self.__gremlin = _gremlin
+
+    @property
+    def bindings(self):
+        return self.__bindings
+
+    @bindings.setter
+    def bindings(self, _bindings):
+        self.__bindings = _bindings
+
+    @property
+    def language(self):
+        return self.__language
+
+    @language.setter
+    def language(self, _language):
+        self.__language = _language
+
+    @property
+    def aliases(self):
+        return self.__aliases
+
+    @aliases.setter
+    def aliases(self, _aliases):
+        self.__aliases = _aliases
+
+    def __repr__(self):
+        res = f"gremlin: {self.__gremlin}, bindings: {self.__bindings}," \
+              f"language: {self.__language}, aliases: {self.__aliases}"
+        return res
+
+    def to_json(self):
+        return json.dumps(self, cls=GremlinDataEncoder)
+
+
+class GremlinDataEncoder(json.JSONEncoder):
+
+    def default(self, o):
+        return {k.split('__')[1]: v for k, v in vars(o).items()}
diff --git a/hugegraph-python-client/src/tests/__init__.py 
b/hugegraph-python-client/src/tests/__init__.py
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/hugegraph-python-client/src/tests/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/hugegraph-python-client/src/tests/api/__init__.py 
b/hugegraph-python-client/src/tests/api/__init__.py
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/hugegraph-python-client/src/tests/api/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/hugegraph-python-client/src/tests/api/test_gremlin.py 
b/hugegraph-python-client/src/tests/api/test_gremlin.py
new file mode 100644
index 0000000..45d36ad
--- /dev/null
+++ b/hugegraph-python-client/src/tests/api/test_gremlin.py
@@ -0,0 +1,92 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import unittest
+
+import pytest
+
+from pyhugegraph.utils.exceptions import NotFoundError
+from tests.client_utils import ClientUtils
+
+
+class TestGremlin(unittest.TestCase):
+
+    client = None
+    gremlin = None
+
+    @classmethod
+    def setUpClass(cls):
+        cls.client = ClientUtils()
+        cls.client.clear_graph_all_data()
+        cls.gremlin = cls.client.gremlin
+        cls.client.init_property_key()
+        cls.client.init_vertex_label()
+        cls.client.init_edge_label()
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.client.clear_graph_all_data()
+
+    def setUp(self):
+        self.client.init_vertices()
+        self.client.init_edges()
+
+    def tearDown(self):
+        pass
+
+    def test_query_all_vertices(self):
+        vertices = self.gremlin.exec('g.V()')
+        lst = vertices.get('data', [])
+        assert 6 == len(lst)
+
+        self.gremlin.exec('g.V().drop()')
+        vertices = self.gremlin.exec('g.V()')
+        lst = vertices.get('data', [])
+        assert 0 == len(lst)
+
+    def test_query_all_edges(self):
+        edges = self.gremlin.exec('g.E()')
+        lst = edges.get('data', [])
+        assert 6 == len(lst)
+
+        self.gremlin.exec('g.E().drop()')
+        edges = self.gremlin.exec('g.E()')
+        lst = edges.get('data', [])
+        assert 0 == len(lst)
+
+    def test_primitive_object(self):
+        result = self.gremlin.exec('1 + 2')
+        print(result)
+        result_set = result.get('data', [])
+        assert 1 == len(result_set)
+
+        data = result_set[0]
+        assert isinstance(data, int)
+        assert 3 == data
+
+    def test_empty_result_set(self):
+        result = self.gremlin.exec('g.V().limit(0)')
+        lst = result.get('data', [])
+        assert 0 == len(lst)
+
+    def test_invalid_gremlin(self):
+        with pytest.raises(NotFoundError):
+            assert self.gremlin.exec('g.V2()')
+
+    def test_security_operation(self):
+        with pytest.raises(NotFoundError):
+            assert self.gremlin.exec('System.exit(-1)')
diff --git a/hugegraph-python-client/src/tests/api/test_variable.py 
b/hugegraph-python-client/src/tests/api/test_variable.py
new file mode 100644
index 0000000..cf73b99
--- /dev/null
+++ b/hugegraph-python-client/src/tests/api/test_variable.py
@@ -0,0 +1,82 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import unittest
+
+import pytest
+
+from pyhugegraph.utils.exceptions import NotFoundError
+from tests.client_utils import ClientUtils
+
+
+class TestVariable(unittest.TestCase):
+
+    client = None
+    variable = None
+
+    @classmethod
+    def setUpClass(cls):
+        cls.client = ClientUtils()
+        cls.variable = cls.client.variable
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.client.clear_graph_all_data()
+
+    def setUp(self):
+        self.client.clear_graph_all_data()
+
+    def tearDown(self):
+        pass
+
+    def test_all(self):
+        assert 0 == len(self.variable.all())
+        self.variable.set('student', 'mary')
+        self.variable.set('price', 20.86)
+
+        dic = self.variable.all()
+        assert 2 == len(dic)
+        assert 'mary' == dic.get('student', None)
+        assert 20.86 == dic.get('price', None)
+
+    def test_remove(self):
+        self.variable.set('lang', 'java')
+        dic = self.variable.all()
+        assert 1 == len(dic)
+        assert 'java' == dic.get('lang', None)
+
+        self.variable.remove('lang')
+        dic = self.variable.all()
+        assert 0 == len(dic)
+        assert dic.get('lang', None) is None
+
+    def test_set_and_get(self):
+        self.variable.set('name', 'tom')
+        self.variable.set('age', 18)
+
+        assert 2 == len(self.variable.all())
+        name = self.variable.get('name').get('name', None)
+        assert 'tom' == name
+        age = self.variable.get('age').get('age', None)
+        assert 18 == age
+
+    def test_get_key_not_exist(self):
+        with pytest.raises(NotFoundError):
+            assert self.variable.get('id').get('id') is None
+
+    def test_remove_key_not_exist(self):
+        self.variable.remove('id')
diff --git a/hugegraph-python-client/src/tests/client_utils.py 
b/hugegraph-python-client/src/tests/client_utils.py
new file mode 100644
index 0000000..166b526
--- /dev/null
+++ b/hugegraph-python-client/src/tests/client_utils.py
@@ -0,0 +1,101 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from pyhugegraph.client import PyHugeClient
+
+
+class ClientUtils:
+    IP = "127.0.0.1"
+    PORT = 8080
+    GRAPH = "hugegraph"
+    USERNAME = 'admin'
+    PASSWORD = 'admin'
+    TIMEOUT = 10
+
+    def __init__(self):
+        self.client = PyHugeClient(self.IP, self.PORT, user=self.USERNAME,
+                                   pwd=self.PASSWORD, graph=self.GRAPH)
+        assert self.client is not None
+
+        self.schema = self.client.schema()
+        self.gremlin = self.client.gremlin()
+        self.graph = self.client.graph()
+        self.graphs = self.client.graphs()
+        self.variable = self.client.variable()
+
+    def init_property_key(self):
+        schema = self.schema
+        schema.propertyKey("name").asText().ifNotExist().create()
+        schema.propertyKey("age").asInt().ifNotExist().create()
+        schema.propertyKey("city").asText().ifNotExist().create()
+        schema.propertyKey("lang").asText().ifNotExist().create()
+        schema.propertyKey("date").asDate().ifNotExist().create()
+        schema.propertyKey("price").asInt().ifNotExist().create()
+        schema.propertyKey("weight").asDouble().ifNotExist().create()
+
+    def init_vertex_label(self):
+        schema = self.schema
+        schema.vertexLabel("person").properties("name", "age", 
"city").primaryKeys("name") \
+            .nullableKeys("city").ifNotExist().create()
+        schema.vertexLabel("software").properties("name", "lang", 
"price").primaryKeys("name") \
+            .nullableKeys("price").ifNotExist().create()
+        schema.vertexLabel("book").useCustomizeStringId().properties("name", 
"price") \
+            .nullableKeys("price").ifNotExist().create()
+
+    def init_edge_label(self):
+        schema = self.schema
+        schema.edgeLabel("knows").sourceLabel("person").targetLabel("person") \
+            .multiTimes().properties("date", "city").sortKeys("date") \
+            .nullableKeys("city").ifNotExist().create()
+        
schema.edgeLabel("created").sourceLabel("person").targetLabel("software") \
+            .properties("date", 
"city").nullableKeys("city").ifNotExist().create()
+
+    def init_vertices(self):
+        graph = self.graph
+        graph.addVertex("person", {"name": "marko", "age": 29, "city": 
"Beijing"})
+        graph.addVertex("person", {"name": "vadas", "age": 27, "city": 
"Hongkong"})
+        graph.addVertex("software", {"name": "lop", "lang": "java", "price": 
328})
+        graph.addVertex("person", {"name": "josh", "age": 32, "city": 
"Beijing"})
+        graph.addVertex("software", {"name": "ripple", "lang": "java", 
"price": 199})
+        graph.addVertex("person", {"name": "peter", "age": 29, "city": 
"Shanghai"})
+
+    def init_edges(self):
+        marko_id = self._get_vertex_id("person", {"name": "marko"})
+        vadas_id = self._get_vertex_id("person", {"name": "vadas"})
+        josh_id = self._get_vertex_id("person", {"name": "josh"})
+        peter_id = self._get_vertex_id("person", {"name": "peter"})
+        lop_id = self._get_vertex_id("software", {"name": "lop"})
+        ripple_id = self._get_vertex_id("software", {"name": "ripple"})
+
+        self.graph.addEdge("knows", marko_id, vadas_id, {"date": "2012-01-10"})
+        self.graph.addEdge("knows", marko_id, josh_id, {"date": "2013-01-10"})
+        self.graph.addEdge("created", marko_id, lop_id, {"date": "2014-01-10", 
"city": "Shanghai"})
+        self.graph.addEdge("created", josh_id, ripple_id, {"date": 
"2015-01-10", "city": "Beijing"})
+        self.graph.addEdge("created", josh_id, lop_id, {"date": "2016-01-10", 
"city": "Beijing"})
+        self.graph.addEdge("created", peter_id, lop_id, {"date": "2017-01-10", 
"city": "Hongkong"})
+
+    def _get_vertex_id(self, label, properties):
+        res = self._get_vertex(label, properties)
+        return res.id
+
+    def _get_vertex(self, label, properties):
+        lst = self.graph.getVertexByCondition(label=label, limit=1, 
properties=properties)
+        assert 1 == len(lst), "Can't find vertex."
+        return lst[0]
+
+    def clear_graph_all_data(self):
+        self.graphs.clear_graph_all_data()

Reply via email to