From 15ae68f5d72babf0e85af0cb300666c101adc763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Wed, 27 Oct 2021 14:13:49 +0200 Subject: [PATCH 1/5] commit received implementation --- .gitignore | 2 ++ example/stream_copy.py | 56 ++++++++++++++++++++++++++++++ specklepy/api/resources/commit.py | 37 ++++++++++++++++++++ tests/test_commit.py | 57 +++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 example/stream_copy.py diff --git a/.gitignore b/.gitignore index 35b9079..5fde443 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.tool-versions + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/example/stream_copy.py b/example/stream_copy.py new file mode 100644 index 0000000..19714a8 --- /dev/null +++ b/example/stream_copy.py @@ -0,0 +1,56 @@ +from gql.transport import transport +from specklepy.api.client import SpeckleClient +from specklepy.api.credentials import ( + StreamWrapper, + get_default_account, + get_local_accounts, +) +from specklepy.api import operations + +if __name__ == "__main__": + # initialise the client + xyz_client = SpeckleClient(host="speckle.xyz") # or whatever your host is + # client = SpeckleClient(host="localhost:3000", use_ssl=False) or use local server + + # authenticate the client with a token + xyz_client.authenticate( + token=[acc for acc in get_local_accounts() if acc.userInfo.id != "4d722975bc"][ + 0 + ].token + ) + + stream = xyz_client.stream.get(id="81d2f2c135") + print(stream) + + local_client = SpeckleClient(host="localhost:3000", use_ssl=False) + local_client.authenticate( + token=[acc for acc in get_local_accounts() if acc.userInfo.id == "4d722975bc"][ + 0 + ].token + ) + + local_stream_id = local_client.stream.create(stream.name) + print(local_stream_id) + + remote_commits = xyz_client.commit.list(stream.id) + + local_wrapper = StreamWrapper(f"http://localhost:3000/streams/{local_stream_id}") + + for remote_commit in remote_commits: + xyz_wrapper = StreamWrapper( + f"https://speckle.xyz/streams/{stream.id}/commits/{remote_commit.id}" + ) + + received_object = operations.receive( + remote_commit.referencedObject, xyz_wrapper.get_transport() + ) + + sent_object_id = operations.send( + received_object, [local_wrapper.get_transport()] + ) + + commit_id = local_client.commit.create(local_stream_id, sent_object_id) + + # xyz_client.object.get() + + print(commit_id) \ No newline at end of file diff --git a/specklepy/api/resources/commit.py b/specklepy/api/resources/commit.py index 7b8e0cb..3d3efe5 100644 --- a/specklepy/api/resources/commit.py +++ b/specklepy/api/resources/commit.py @@ -185,3 +185,40 @@ class Resource(ResourceBase): return self.make_request( query=query, params=params, return_type="commitDelete", parse_response=False ) + + def received( + self, + stream_id: str, + commit_id: str, + source_application: str = "python", + message: Optional[str] = None, + ) -> bool: + """ + Mark a commit object a received by the source application. + """ + query = gql( + """ + mutation CommitReceive($receivedInput:CommitReceivedInput!){ + commitReceive(input:$receivedInput) + } + """ + ) + params = { + "receivedInput": { + "sourceApplication": source_application, + "streamId": stream_id, + "commitId": commit_id, + "message": "message", + } + } + + try: + return self.make_request( + query=query, + params=params, + return_type="commitReceive", + parse_response=False, + ) + except Exception as ex: + print(ex.with_traceback) + return False diff --git a/tests/test_commit.py b/tests/test_commit.py index ef95191..698fd19 100644 --- a/tests/test_commit.py +++ b/tests/test_commit.py @@ -1,7 +1,9 @@ +from typing import Dict, List import pytest from specklepy.api import operations from specklepy.api.models import Commit, Stream from specklepy.transports.server.server import ServerTransport +from gql import gql @pytest.mark.run(order=4) @@ -68,3 +70,58 @@ class TestCommit: deleted = client.commit.delete(stream_id=stream.id, commit_id=commit_id) assert deleted is True + + def _get_commit_activity(self, client, stream_id, commit_id) -> List[Dict]: + return client.httpclient.execute( + gql( + """ + query Commit($stream_id: String!, $commit_id: String!) { + stream(id: $stream_id) { + commit(id: $commit_id) { + id + referencedObject + message + authorId + authorName + authorAvatar + branchName + createdAt + sourceApplication + totalChildrenCount + parents + activity { + items { + userId + actionType + info + } + } + } + } + } + """ + ), + variable_values={"stream_id": stream_id, "commit_id": commit_id}, + )["stream"]["commit"]["activity"] + + def test_commit_marked_as_received(self, client, stream, mesh) -> None: + commit = Commit(message="this commit should be received") + commit.id = client.commit.create( + stream_id=stream.id, + object_id=mesh.id, + message=commit.message, + ) + + activity = self._get_commit_activity(client, stream.id, commit.id) + + assert len(activity) == 1 + assert ( + client.commit.received( + stream.id, + commit.id, + source_application="pytest", + message="testing received", + ) + == True + ) + assert len(activity) == 2 From a89b12a02c3d7bb46dbb80feb8383f475c88fd27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Wed, 27 Oct 2021 19:16:08 +0200 Subject: [PATCH 2/5] remove receive server test --- example/stream_copy.py | 2 +- pyproject.toml | 2 +- specklepy/api/credentials.py | 2 +- specklepy/logging/exceptions.py | 2 +- specklepy/logging/metrics.py | 2 +- tests/test_commit.py | 54 ++--------- tests/test_geometry.py | 163 ++++++++++++++++++++++---------- tests/test_objects.py | 14 +-- tests/test_serialization.py | 3 +- 9 files changed, 129 insertions(+), 115 deletions(-) diff --git a/example/stream_copy.py b/example/stream_copy.py index 19714a8..3835822 100644 --- a/example/stream_copy.py +++ b/example/stream_copy.py @@ -53,4 +53,4 @@ if __name__ == "__main__": # xyz_client.object.get() - print(commit_id) \ No newline at end of file + print(commit_id) diff --git a/pyproject.toml b/pyproject.toml index acb53f2..a931b18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "specklepy" -version = "2.1.0" +version = "2.2.0" description = "The Python SDK for Speckle 2.0" readme = "README.md" authors = ["Speckle Systems "] diff --git a/specklepy/api/credentials.py b/specklepy/api/credentials.py index ae72d5b..3bdc188 100644 --- a/specklepy/api/credentials.py +++ b/specklepy/api/credentials.py @@ -227,4 +227,4 @@ class StreamWrapper: """ if not self.client or not self.client.me: self.get_client(token) - return ServerTransport(self.stream_id, self.client) \ No newline at end of file + return ServerTransport(self.stream_id, self.client) diff --git a/specklepy/logging/exceptions.py b/specklepy/logging/exceptions.py index 5c690e0..1f6adf8 100644 --- a/specklepy/logging/exceptions.py +++ b/specklepy/logging/exceptions.py @@ -32,4 +32,4 @@ class GraphQLException(SpeckleException): class SpeckleWarning(Warning): def __init__(self, *args: object) -> None: - super().__init__(*args) \ No newline at end of file + super().__init__(*args) diff --git a/specklepy/logging/metrics.py b/specklepy/logging/metrics.py index 44a191e..89c688d 100644 --- a/specklepy/logging/metrics.py +++ b/specklepy/logging/metrics.py @@ -122,4 +122,4 @@ class MetricsTracker(metaclass=Singleton): except Exception as ex: LOG.error("Error sending metrics request: " + str(ex)) - self.queue.task_done() \ No newline at end of file + self.queue.task_done() diff --git a/tests/test_commit.py b/tests/test_commit.py index 698fd19..ce22237 100644 --- a/tests/test_commit.py +++ b/tests/test_commit.py @@ -1,9 +1,7 @@ -from typing import Dict, List import pytest from specklepy.api import operations from specklepy.api.models import Commit, Stream from specklepy.transports.server.server import ServerTransport -from gql import gql @pytest.mark.run(order=4) @@ -71,39 +69,6 @@ class TestCommit: assert deleted is True - def _get_commit_activity(self, client, stream_id, commit_id) -> List[Dict]: - return client.httpclient.execute( - gql( - """ - query Commit($stream_id: String!, $commit_id: String!) { - stream(id: $stream_id) { - commit(id: $commit_id) { - id - referencedObject - message - authorId - authorName - authorAvatar - branchName - createdAt - sourceApplication - totalChildrenCount - parents - activity { - items { - userId - actionType - info - } - } - } - } - } - """ - ), - variable_values={"stream_id": stream_id, "commit_id": commit_id}, - )["stream"]["commit"]["activity"] - def test_commit_marked_as_received(self, client, stream, mesh) -> None: commit = Commit(message="this commit should be received") commit.id = client.commit.create( @@ -112,16 +77,11 @@ class TestCommit: message=commit.message, ) - activity = self._get_commit_activity(client, stream.id, commit.id) - - assert len(activity) == 1 - assert ( - client.commit.received( - stream.id, - commit.id, - source_application="pytest", - message="testing received", - ) - == True + commit_marked_received = client.commit.received( + stream.id, + commit.id, + source_application="pytest", + message="testing received", ) - assert len(activity) == 2 + + assert commit_marked_received == True diff --git a/tests/test_geometry.py b/tests/test_geometry.py index 673930e..2674128 100644 --- a/tests/test_geometry.py +++ b/tests/test_geometry.py @@ -5,11 +5,28 @@ import pytest from specklepy.api import operations from specklepy.objects.base import Base from specklepy.objects.encoding import CurveArray, ObjectArray -from specklepy.objects.geometry import (Arc, Box, Brep, BrepEdge, BrepFace, - BrepLoop, BrepTrim, BrepTrimTypeEnum, - Circle, Curve, Ellipse, Interval, Line, - Mesh, Plane, Point, Polycurve, - Polyline, Surface, Vector) +from specklepy.objects.geometry import ( + Arc, + Box, + Brep, + BrepEdge, + BrepFace, + BrepLoop, + BrepTrim, + BrepTrimTypeEnum, + Circle, + Curve, + Ellipse, + Interval, + Line, + Mesh, + Plane, + Point, + Polycurve, + Polyline, + Surface, + Vector, +) from specklepy.transports.memory import MemoryTransport @@ -71,7 +88,7 @@ def arc(plane, interval): angleRadians=33, plane=plane, domain=interval, - units='m', + units="m", # These attributes are not handled in C# # bbox=None, # area=None, @@ -88,7 +105,7 @@ def circle(plane, interval): radius=22, plane=plane, domain=interval, - units='m', + units="m", # These attributes are not handled in C# # bbox=None, # area=None, @@ -103,7 +120,7 @@ def ellipse(plane, interval): secondRadius=22, plane=plane, domain=interval, - units='m', + units="m", # These attributes are not handled in C# # trimDomain=None, # bbox=None, @@ -118,7 +135,7 @@ def polyline(interval): value=[22, 44, 54.3, 99, 232, 21], closed=True, domain=interval, - units='m', + units="m", # These attributes are not handled in C# # bbox=None, # area=None, @@ -137,7 +154,7 @@ def curve(interval): points=[23, 21, 44, 43, 56, 76, 1, 3, 2], weights=[23, 11, 23], knots=[22, 45, 76, 11], - units='m', + units="m", # These attributes are not handled in C# # displayValue=None, # bbox=None, @@ -152,7 +169,7 @@ def polycurve(interval, curve, polyline): segments=[curve, polyline], domain=interval, closed=True, - units='m', + units="m", # These attributes are not handled in C# # bbox=None, # area=None, @@ -187,7 +204,7 @@ def surface(interval): domainV=interval, knotsU=[1.1, 2.2, 3.3, 4.4], knotsV=[9, 8, 7, 6, 5, 4.4], - units='m', + units="m", # These attributes are not handled in C# # bbox=None, # area=None, @@ -218,11 +235,7 @@ def brep_edge(interval): @pytest.fixture() def brep_loop(): - return BrepLoop( - FaceIndex=5, - TrimIndices=[3, 4, 5], - Type='unknown' - ) + return BrepLoop(FaceIndex=5, TrimIndices=[3, 4, 5], Type="unknown") @pytest.fixture() @@ -235,7 +248,7 @@ def brep_trim(): LoopIndex=4, CurveIndex=7, IsoStatus=6, - TrimType='Mated', + TrimType="Mated", IsReversed=False, # These attributes are not handled in C# # Domain=None, @@ -243,10 +256,21 @@ def brep_trim(): @pytest.fixture -def brep(mesh, box, surface, curve, polyline, circle, point, - brep_edge, brep_loop, brep_trim, brep_face): +def brep( + mesh, + box, + surface, + curve, + polyline, + circle, + point, + brep_edge, + brep_loop, + brep_trim, + brep_face, +): return Brep( - provenance='pytest', + provenance="pytest", bbox=box, area=32, volume=54, @@ -265,33 +289,57 @@ def brep(mesh, box, surface, curve, polyline, circle, point, @pytest.fixture -def geometry_objects_dict(point, vector, plane, line, arc, - circle, ellipse, polyline, curve, - polycurve, surface, brep_trim): +def geometry_objects_dict( + point, + vector, + plane, + line, + arc, + circle, + ellipse, + polyline, + curve, + polycurve, + surface, + brep_trim, +): return { - 'point': point, - 'vector': vector, - 'plane': plane, - 'line': line, - 'arc': arc, - 'circle': circle, - 'ellipse': ellipse, - 'polyline': polyline, - 'curve': curve, - 'polycurve': polycurve, - 'surface': surface, - 'brep_trim': brep_trim + "point": point, + "vector": vector, + "plane": plane, + "line": line, + "arc": arc, + "circle": circle, + "ellipse": ellipse, + "polyline": polyline, + "curve": curve, + "polycurve": polycurve, + "surface": surface, + "brep_trim": brep_trim, } -@pytest.mark.parametrize('object_name', [ - 'point', 'vector', 'plane', 'line', 'arc', 'circle', - 'ellipse', 'polyline', 'curve', 'polycurve', 'surface', 'brep_trim' -]) +@pytest.mark.parametrize( + "object_name", + [ + "point", + "vector", + "plane", + "line", + "arc", + "circle", + "ellipse", + "polyline", + "curve", + "polycurve", + "surface", + "brep_trim", + ], +) def test_to_and_from_list(object_name: str, geometry_objects_dict): object = geometry_objects_dict[object_name] - assert hasattr(object, 'to_list') - assert hasattr(object, 'from_list') + assert hasattr(object, "to_list") + assert hasattr(object, "from_list") chunks = object.to_list() assert isinstance(chunks, list) @@ -306,8 +354,7 @@ def test_brep_surfaces_value_serialization(surface): assert brep.Surfaces == None assert brep.SurfacesValue == None brep.Surfaces = [surface, surface] - assert brep.SurfacesValue == ObjectArray.from_objects( - [surface, surface]).data + assert brep.SurfacesValue == ObjectArray.from_objects([surface, surface]).data brep.SurfacesValue = ObjectArray.from_objects([surface]).data assert len(brep.Surfaces) == 1 @@ -341,16 +388,32 @@ def test_brep_curve3d_values_serialization(curve, polyline, circle): def test_brep_vertices_values_serialization(): brep = Brep() brep.VerticesValue = [1, 1, 1, 1, 2, 2, 2, 3, 3, 3] - brep.Vertices[0].get_id() == Point(x=1, y=1, z=1, _units='mm').get_id() - brep.Vertices[1].get_id() == Point(x=2, y=2, z=2, _units='mm').get_id() - brep.Vertices[2].get_id() == Point(x=3, y=3, z=3, _units='mm').get_id() + brep.Vertices[0].get_id() == Point(x=1, y=1, z=1, _units="mm").get_id() + brep.Vertices[1].get_id() == Point(x=2, y=2, z=2, _units="mm").get_id() + brep.Vertices[2].get_id() == Point(x=3, y=3, z=3, _units="mm").get_id() def test_trims_value_serialization(): brep = Brep() brep.TrimsValue = [ - 0, 0, 0, 0, 0, 0, 1, 1, 1, - 1, 0, 0, 0, 0, 1, 2, 1, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, ] brep.Trims[0].get_id() == BrepTrim( @@ -383,7 +446,7 @@ def test_serialized_brep_attributes(brep: Brep): serialized = operations.serialize(brep, [transport]) serialized_dict = json.loads(serialized) - removed_keys = ['Surfaces', 'Curve3D', 'Curve2D', 'Vertices', 'Trims'] + removed_keys = ["Surfaces", "Curve3D", "Curve2D", "Vertices", "Trims"] for k in removed_keys: assert k not in serialized_dict.keys() diff --git a/tests/test_objects.py b/tests/test_objects.py index d5cd872..1018b71 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -21,11 +21,9 @@ class TestObject: def test_object_create(self, client, stream, base): transport = SQLiteTransport() - s = BaseObjectSerializer( - write_transports=[transport], read_transport=transport) + s = BaseObjectSerializer(write_transports=[transport], read_transport=transport) _, base_dict = s.traverse_base(base) - obj_id = client.object.create( - stream_id=stream.id, objects=[base_dict])[0] + obj_id = client.object.create(stream_id=stream.id, objects=[base_dict])[0] assert isinstance(obj_id, str) assert base_dict["@detach"]["speckle_type"] == "reference" @@ -43,12 +41,6 @@ class TestObject: def test_object_array_decoder(self): array = ObjectArray() - array.data = [ - 5, 1, 1, 1, 1, 1, - 4, 1, 1, 1, 1, - 3, 1, 1, 1, - 2, 1, 1, - 1, 1 - ] + array.data = [5, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 3, 1, 1, 1, 2, 1, 1, 1, 1] assert array.decode(decoder=sum) == [5, 4, 3, 2, 1] diff --git a/tests/test_serialization.py b/tests/test_serialization.py index 60d93eb..14be28d 100644 --- a/tests/test_serialization.py +++ b/tests/test_serialization.py @@ -1,5 +1,4 @@ import json -from attr import has import pytest from specklepy.api import operations from specklepy.transports.server import ServerTransport @@ -89,4 +88,4 @@ class TestSerialization: untyped = '{"foo": "bar"}' deserialised = operations.deserialize(untyped) - assert deserialised == {"foo": "bar"} \ No newline at end of file + assert deserialised == {"foo": "bar"} From a7d31d49838a2db8690fe6c728c8529cac9d7190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= <57442769+gjedlicska@users.noreply.github.com> Date: Wed, 27 Oct 2021 19:18:45 +0200 Subject: [PATCH 3/5] Delete stream_copy.py --- example/stream_copy.py | 56 ------------------------------------------ 1 file changed, 56 deletions(-) delete mode 100644 example/stream_copy.py diff --git a/example/stream_copy.py b/example/stream_copy.py deleted file mode 100644 index 3835822..0000000 --- a/example/stream_copy.py +++ /dev/null @@ -1,56 +0,0 @@ -from gql.transport import transport -from specklepy.api.client import SpeckleClient -from specklepy.api.credentials import ( - StreamWrapper, - get_default_account, - get_local_accounts, -) -from specklepy.api import operations - -if __name__ == "__main__": - # initialise the client - xyz_client = SpeckleClient(host="speckle.xyz") # or whatever your host is - # client = SpeckleClient(host="localhost:3000", use_ssl=False) or use local server - - # authenticate the client with a token - xyz_client.authenticate( - token=[acc for acc in get_local_accounts() if acc.userInfo.id != "4d722975bc"][ - 0 - ].token - ) - - stream = xyz_client.stream.get(id="81d2f2c135") - print(stream) - - local_client = SpeckleClient(host="localhost:3000", use_ssl=False) - local_client.authenticate( - token=[acc for acc in get_local_accounts() if acc.userInfo.id == "4d722975bc"][ - 0 - ].token - ) - - local_stream_id = local_client.stream.create(stream.name) - print(local_stream_id) - - remote_commits = xyz_client.commit.list(stream.id) - - local_wrapper = StreamWrapper(f"http://localhost:3000/streams/{local_stream_id}") - - for remote_commit in remote_commits: - xyz_wrapper = StreamWrapper( - f"https://speckle.xyz/streams/{stream.id}/commits/{remote_commit.id}" - ) - - received_object = operations.receive( - remote_commit.referencedObject, xyz_wrapper.get_transport() - ) - - sent_object_id = operations.send( - received_object, [local_wrapper.get_transport()] - ) - - commit_id = local_client.commit.create(local_stream_id, sent_object_id) - - # xyz_client.object.get() - - print(commit_id) From 8f7d4b2ca735fbbc1ad7a4264cd3ca31576073b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Wed, 27 Oct 2021 19:20:04 +0200 Subject: [PATCH 4/5] add 3.10 as target --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9f91db2..d16979b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -55,7 +55,7 @@ workflows: - test: matrix: parameters: - tag: ["3.6", "3.7", "3.8", "3.9"] + tag: ["3.6", "3.7", "3.8", "3.9", "3.10"] filters: tags: only: /.*/ From 219456f5f8c6705c4eae77a823d106dd3f2493c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= Date: Wed, 27 Oct 2021 20:28:01 +0200 Subject: [PATCH 5/5] circleci py310 is not working --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d16979b..9f91db2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -55,7 +55,7 @@ workflows: - test: matrix: parameters: - tag: ["3.6", "3.7", "3.8", "3.9", "3.10"] + tag: ["3.6", "3.7", "3.8", "3.9"] filters: tags: only: /.*/