style(whole-project): fixing linting and typing errors

This commit is contained in:
Gergő Jedlicska
2022-12-20 10:45:22 +01:00
parent b25f2ab4bc
commit 990cf4eb2f
41 changed files with 505 additions and 236 deletions
+8 -2
View File
@@ -1,4 +1,9 @@
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
hooks:
- id: ruff
rev: v0.0.186
- repo: https://github.com/commitizen-tools/commitizen
hooks:
- id: commitizen
@@ -8,9 +13,10 @@ repos:
rev: v2.38.0
- repo: https://github.com/pycqa/isort
rev: 5.10.1
rev: v5.11.3
hooks:
- id: isort
- repo: https://github.com/psf/black
rev: 22.12.0
hooks:
@@ -21,7 +27,7 @@ repos:
# https://pre-commit.com/#top_level-default_language_version
# language_version: python3.11
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
rev: v4.4.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
-1
View File
@@ -27,7 +27,6 @@ def clean_db():
def one_pass(clean: bool, randomize: bool, child_count: int):
foo = Base()
for i in range(child_count):
stuff = random_string() if randomize else "stuff"
+15
View File
@@ -0,0 +1,15 @@
from devtools import debug
from specklepy.api import operations
from specklepy.api.wrapper import StreamWrapper
if __name__ == "__main__":
stream_url = "https://latest.speckle.dev/streams/7d051a6449"
wrapper = StreamWrapper(stream_url)
transport = wrapper.get_transport()
rec = operations.receive("98396753f8bf7fe1cb60c5193e9f9d86", transport)
# hash = operations.send(base=foo, transports=[transport], use_default_cache=False)
debug(rec)
-1
View File
@@ -25,7 +25,6 @@ def create_object(child_count: int) -> Base:
if __name__ == "__main__":
stream_url = "http://hyperion:3000/streams/2372b54c35"
child_count = 10
+1 -1
View File
@@ -9,7 +9,7 @@ def patch(tag):
lines = f.readlines()
if "version" not in lines[2]:
raise Exception(f"Invalid pyproject.toml. Could not patch version.")
raise Exception("Invalid pyproject.toml. Could not patch version.")
lines[2] = f'version = "{tag}"\n'
with open("pyproject.toml", "w") as file:
Generated
+51 -1
View File
@@ -1172,6 +1172,32 @@ files = [
[package.dependencies]
requests = ">=2.0.1,<3.0.0"
[[package]]
name = "ruff"
version = "0.0.187"
description = "An extremely fast Python linter, written in Rust."
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "ruff-0.0.187-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:d90cbd30c585a9551695af09c91c07542a4bfebe9870f8ca4de5d9ac34478665"},
{file = "ruff-0.0.187-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:bca4d85f182c7452f5b607e99c03a0957126bfb260815b824f7fabde519708d8"},
{file = "ruff-0.0.187-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c498a7e183c2cd58e8cc0bed93d88e44305365a93132463911680d20d158ae8a"},
{file = "ruff-0.0.187-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb525861aae5b005e92c7f32dff8382bbd13a2da5a06b950a11ba879bb9fef15"},
{file = "ruff-0.0.187-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41cfed788d5f8bd618710432583b0f61195769919e8bc1a77f080d5db2ebbb93"},
{file = "ruff-0.0.187-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:25a9f74ee9b9472b750c7f0e25551b6f3b298a62126d0386bc9bdda1fed00c35"},
{file = "ruff-0.0.187-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:24d0e61041abd2811cf841b43572fed1d0343e96704aedfac388f03dc2f1f53e"},
{file = "ruff-0.0.187-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88722ddbeec8614c9a5fd90eac3aa13372ede98559c36ef95581a26954a85fb5"},
{file = "ruff-0.0.187-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9032f221d28897852c5de173cd6890185f4c86a93eca4ed0c215076e8f0f626"},
{file = "ruff-0.0.187-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:11833a0e80ff9d244d11c16cc4d1283e84cf0ac47f2440d88093ee3076687fcb"},
{file = "ruff-0.0.187-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:debcd3740da13b786656fcf23caa1a328c678b19ab822243bd00a25efb00ab7b"},
{file = "ruff-0.0.187-py3-none-musllinux_1_2_i686.whl", hash = "sha256:51f4bf4940a57b4e04254f2823a0e4de52595987c65e0c9ed7b4546c5362f60e"},
{file = "ruff-0.0.187-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ab7e50ba517f3bfaaadaba3f9e68e0a95ff04abab5c480f05015a156f58f16d3"},
{file = "ruff-0.0.187-py3-none-win32.whl", hash = "sha256:25e55cc000ca6fe83df6d25080adec86acb3a39cd623ed9ff122ccede02ab6ba"},
{file = "ruff-0.0.187-py3-none-win_amd64.whl", hash = "sha256:a81acd2b111b267cda09c507ad72a7ca47fa6f47e1ec240e594eef37db1bdf8d"},
{file = "ruff-0.0.187.tar.gz", hash = "sha256:d209efb6cb4f03b31c76d7be770cb387cbdf0592c604f0d0639c1a6f742db04c"},
]
[[package]]
name = "setuptools"
version = "65.6.3"
@@ -1286,6 +1312,30 @@ files = [
{file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"},
]
[[package]]
name = "types-deprecated"
version = "1.2.9"
description = "Typing stubs for Deprecated"
category = "dev"
optional = false
python-versions = "*"
files = [
{file = "types-Deprecated-1.2.9.tar.gz", hash = "sha256:e04ce58929509865359e91dcc38720123262b4cd68fa2a8a90312d50390bb6fa"},
{file = "types_Deprecated-1.2.9-py3-none-any.whl", hash = "sha256:53d05621e1d75de537f5a57d93508c8df17e37c07ee60b9fb09d39e1b7586c1e"},
]
[[package]]
name = "types-ujson"
version = "5.6.0.0"
description = "Typing stubs for ujson"
category = "dev"
optional = false
python-versions = "*"
files = [
{file = "types-ujson-5.6.0.0.tar.gz", hash = "sha256:1a20cf7946772756736582612e0da5656d2dbeccd24be4c1e97d1e66b072b97e"},
{file = "types_ujson-5.6.0.0-py3-none-any.whl", hash = "sha256:010b221260c24a915c6e713a83f366b91390766850ec110304de5b20c86b4b11"},
]
[[package]]
name = "typing-extensions"
version = "4.4.0"
@@ -1670,4 +1720,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools"
[metadata]
lock-version = "2.0"
python-versions = ">=3.7.2, <4.0"
content-hash = "fba4eaa4891e1f626c0d6a04a919985d90a8d0a8bbf334d2846e2a16da28304c"
content-hash = "18bc7c2f98f551538bf1dfca42a0c3c352e98f2c0a7a59619b8fd16bd2c13e39"
+4 -1
View File
@@ -32,6 +32,9 @@ pylint = "^2.14.4"
mypy = "^0.982"
pre-commit = "^2.20.0"
commitizen = "^2.38.0"
ruff = "^0.0.187"
types-deprecated = "^1.2.9"
types-ujson = "^5.6.0.0"
[tool.black]
exclude = '''
@@ -50,7 +53,7 @@ exclude = '''
'''
include = '\.pyi?$'
line-length = 88
target-version = ["py37", "py38", "py39", "py310"]
target-version = ["py37", "py38", "py39", "py310", "py311"]
[tool.commitizen]
+28 -13
View File
@@ -26,10 +26,13 @@ from specklepy.logging.exceptions import SpeckleException, SpeckleWarning
class SpeckleClient:
"""
The `SpeckleClient` is your entry point for interacting with your Speckle Server's GraphQL API.
You'll need to have access to a server to use it, or you can use our public server `speckle.xyz`.
The `SpeckleClient` is your entry point for interacting with
your Speckle Server's GraphQL API.
You'll need to have access to a server to use it,
or you can use our public server `speckle.xyz`.
To authenticate the client, you'll need to have downloaded the [Speckle Manager](https://speckle.guide/#speckle-manager)
To authenticate the client, you'll need to have downloaded
the [Speckle Manager](https://speckle.guide/#speckle-manager)
and added your account.
```py
@@ -92,15 +95,22 @@ class SpeckleClient:
# ) from ex
def __repr__(self):
return f"SpeckleClient( server: {self.url}, authenticated: {self.account.token is not None} )"
return (
f"SpeckleClient( server: {self.url}, authenticated:"
f" {self.account.token is not None} )"
)
@deprecated(
version="2.6.0",
reason="Renamed: please use `authenticate_with_account` or `authenticate_with_token` instead.",
reason=(
"Renamed: please use `authenticate_with_account` or"
" `authenticate_with_token` instead."
),
)
def authenticate(self, token: str) -> None:
"""Authenticate the client using a personal access token
The token is saved in the client object and a synchronous GraphQL entrypoint is created
The token is saved in the client object and a synchronous GraphQL
entrypoint is created
Arguments:
token {str} -- an api token
@@ -109,8 +119,10 @@ class SpeckleClient:
self._set_up_client()
def authenticate_with_token(self, token: str) -> None:
"""Authenticate the client using a personal access token
The token is saved in the client object and a synchronous GraphQL entrypoint is created
"""
Authenticate the client using a personal access token.
The token is saved in the client object and a synchronous GraphQL
entrypoint is created
Arguments:
token {str} -- an api token
@@ -121,10 +133,12 @@ class SpeckleClient:
def authenticate_with_account(self, account: Account) -> None:
"""Authenticate the client using an Account object
The account is saved in the client object and a synchronous GraphQL entrypoint is created
The account is saved in the client object and a synchronous GraphQL
entrypoint is created
Arguments:
account {Account} -- the account object which can be found with `get_default_account` or `get_local_accounts`
account {Account} -- the account object which can be found with
`get_default_account` or `get_local_accounts`
"""
metrics.track(metrics.CLIENT, account, {"name": "authenticate with account"})
self.account = account
@@ -153,7 +167,8 @@ class SpeckleClient:
if self.user.get() is None:
warn(
SpeckleWarning(
f"Possibly invalid token - could not authenticate Speckle Client for server {self.url}"
"Possibly invalid token - could not authenticate Speckle Client"
f" for server {self.url}"
)
)
@@ -167,7 +182,7 @@ class SpeckleClient:
server_version = None
try:
server_version = self.server.version()
except:
except Exception:
pass
self.user = user.Resource(
account=self.account,
@@ -214,7 +229,7 @@ class SpeckleClient:
return attr.Resource(
account=self.account, basepath=self.url, client=self.httpclient
)
except:
except AttributeError:
raise SpeckleException(
f"Method {name} is not supported by the SpeckleClient class"
)
+16 -6
View File
@@ -26,7 +26,10 @@ class Account(BaseModel):
id: Optional[str] = None
def __repr__(self) -> str:
return f"Account(email: {self.userInfo.email}, server: {self.serverInfo.url}, isDefault: {self.isDefault})"
return (
f"Account(email: {self.userInfo.email}, server: {self.serverInfo.url},"
f" isDefault: {self.isDefault})"
)
def __str__(self) -> str:
return self.__repr__()
@@ -45,7 +48,8 @@ def get_local_accounts(base_path: Optional[str] = None) -> List[Account]:
base_path {str} -- custom base path if you are not using the system default
Returns:
List[Account] -- list of all local accounts or an empty list if no accounts were found
List[Account] -- list of all local accounts or an empty list if
no accounts were found
"""
accounts: List[Account] = []
try:
@@ -95,7 +99,9 @@ def get_local_accounts(base_path: Optional[str] = None) -> List[Account]:
def get_default_account(base_path: Optional[str] = None) -> Optional[Account]:
"""Gets this environment's default account if any. If there is no default, the first found will be returned and set as default.
"""
Gets this environment's default account if any. If there is no default,
the first found will be returned and set as default.
Arguments:
base_path {str} -- custom base path if you are not using the system default
@@ -121,7 +127,8 @@ def get_account_from_token(token: str, server_url: str = None) -> Account:
token {str} -- the api token
Returns:
Account -- the local account with this token or a shell account containing just the token and url if no local account is found
Account -- the local account with this token or a shell account containing
just the token and url if no local account is found
"""
accounts = get_local_accounts()
if not accounts:
@@ -145,6 +152,9 @@ def get_account_from_token(token: str, server_url: str = None) -> Account:
class StreamWrapper:
def __init__(self, url: str = None) -> None:
raise SpeckleException(
message="The StreamWrapper has moved as of v2.6.0! Please import from specklepy.api.wrapper",
exception=DeprecationWarning,
message=(
"The StreamWrapper has moved as of v2.6.0! Please import from"
" specklepy.api.wrapper"
),
exception=DeprecationWarning(),
)
+27 -6
View File
@@ -25,7 +25,11 @@ class Commit(BaseModel):
parents: Optional[List[str]]
def __repr__(self) -> str:
return f"Commit( id: {self.id}, message: {self.message}, referencedObject: {self.referencedObject}, authorName: {self.authorName}, branchName: {self.branchName}, createdAt: {self.createdAt} )"
return (
f"Commit( id: {self.id}, message: {self.message}, referencedObject:"
f" {self.referencedObject}, authorName: {self.authorName}, branchName:"
f" {self.branchName}, createdAt: {self.createdAt} )"
)
def __str__(self) -> str:
return self.__repr__()
@@ -75,7 +79,10 @@ class Stream(BaseModel):
favoritesCount: Optional[int] = None
def __repr__(self):
return f"Stream( id: {self.id}, name: {self.name}, description: {self.description}, isPublic: {self.isPublic})"
return (
f"Stream( id: {self.id}, name: {self.name}, description:"
f" {self.description}, isPublic: {self.isPublic})"
)
def __str__(self) -> str:
return self.__repr__()
@@ -99,7 +106,10 @@ class User(BaseModel):
streams: Optional[Streams]
def __repr__(self):
return f"User( id: {self.id}, name: {self.name}, email: {self.email}, company: {self.company} )"
return (
f"User( id: {self.id}, name: {self.name}, email: {self.email}, company:"
f" {self.company} )"
)
def __str__(self) -> str:
return self.__repr__()
@@ -129,7 +139,11 @@ class PendingStreamCollaborator(BaseModel):
token: Optional[str]
def __repr__(self):
return f"PendingStreamCollaborator( inviteId: {self.inviteId}, streamId: {self.streamId}, role: {self.role}, title: {self.title}, invitedBy: {self.user.name if self.user else None})"
return (
f"PendingStreamCollaborator( inviteId: {self.inviteId}, streamId:"
f" {self.streamId}, role: {self.role}, title: {self.title}, invitedBy:"
f" {self.user.name if self.user else None})"
)
def __str__(self) -> str:
return self.__repr__()
@@ -146,7 +160,10 @@ class Activity(BaseModel):
time: Optional[datetime]
def __repr__(self) -> str:
return f"Activity( streamId: {self.streamId}, actionType: {self.actionType}, message: {self.message}, userId: {self.userId} )"
return (
f"Activity( streamId: {self.streamId}, actionType: {self.actionType},"
f" message: {self.message}, userId: {self.userId} )"
)
def __str__(self) -> str:
return self.__repr__()
@@ -158,7 +175,11 @@ class ActivityCollection(BaseModel):
cursor: Optional[datetime]
def __repr__(self) -> str:
return f"ActivityCollection( totalCount: {self.totalCount}, items: {len(self.items) if self.items else 0}, cursor: {self.cursor.isoformat() if self.cursor else None} )"
return (
f"ActivityCollection( totalCount: {self.totalCount}, items:"
f" {len(self.items) if self.items else 0}, cursor:"
f" {self.cursor.isoformat() if self.cursor else None} )"
)
def __str__(self) -> str:
return self.__repr__()
+22 -9
View File
@@ -18,7 +18,8 @@ def send(
Arguments:
obj {Base} -- the object you want to send
transports {list} -- where you want to send them
use_default_cache {bool} -- toggle for the default cache. If set to false, it will only send to the provided transports
use_default_cache {bool} -- toggle for the default cache.
If set to false, it will only send to the provided transports
Returns:
str -- the object id of the sent object
@@ -26,7 +27,10 @@ def send(
if not transports and not use_default_cache:
raise SpeckleException(
message="You need to provide at least one transport: cannot send with an empty transport list and no default cache"
message=(
"You need to provide at least one transport: cannot send with an empty"
" transport list and no default cache"
)
)
if isinstance(transports, AbstractTransport):
@@ -62,7 +66,6 @@ def _untracked_receive(
remote_transport: Optional[AbstractTransport] = None,
local_transport: Optional[AbstractTransport] = None,
) -> Base:
"""Receives an object from a transport.
Arguments:
@@ -86,7 +89,10 @@ def _untracked_receive(
if not remote_transport:
raise SpeckleException(
message="Could not find the specified object using the local transport, and you didn't provide a fallback remote from which to pull it."
message=(
"Could not find the specified object using the local transport, and you"
" didn't provide a fallback remote from which to pull it."
)
)
obj_string = remote_transport.copy_object_and_children(
@@ -98,12 +104,14 @@ def _untracked_receive(
def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str:
"""
Serialize a base object. If no write transports are provided, the object will be serialized
Serialize a base object. If no write transports are provided,
the object will be serialized
without detaching or chunking any of the attributes.
Arguments:
base {Base} -- the object to serialize
write_transports {List[AbstractTransport]} -- optional: the transports to write to
write_transports {List[AbstractTransport]}
-- optional: the transports to write to
Returns:
str -- the serialized object
@@ -118,12 +126,17 @@ def deserialize(
obj_string: str, read_transport: Optional[AbstractTransport] = None
) -> Base:
"""
Deserialize a string object into a Base object. If the object contains referenced child objects that are not stored in the local db, a read transport needs to be provided in order to recompose the base with the children objects.
Deserialize a string object into a Base object.
If the object contains referenced child objects that are not stored in the local db,
a read transport needs to be provided in order to recompose
the base with the children objects.
Arguments:
obj_string {str} -- the string object to deserialize
read_transport {AbstractTransport} -- the transport to fetch children objects from
(defaults to SQLiteTransport)
read_transport {AbstractTransport}
-- the transport to fetch children objects from
(defaults to SQLiteTransport)
Returns:
Base -- the deserialized object
+21 -12
View File
@@ -52,7 +52,7 @@ class ResourceBase(object):
elif self.schema:
try:
return self.schema.parse_obj(response)
except:
except Exception:
s = BaseObjectSerializer(read_transport=SQLiteTransport())
return s.recompose_base(response)
else:
@@ -61,7 +61,7 @@ class ResourceBase(object):
def make_request(
self,
query: DocumentNode,
params: Dict = None,
params: Optional[Dict] = None,
return_type: Union[str, List, None] = None,
schema=None,
parse_response: bool = True,
@@ -72,13 +72,19 @@ class ResourceBase(object):
except Exception as ex:
if isinstance(ex, TransportQueryError):
return GraphQLException(
message=f"Failed to execute the GraphQL {self.name} request. Errors: {ex.errors}",
message=(
f"Failed to execute the GraphQL {self.name} request. Errors:"
f" {ex.errors}"
),
errors=ex.errors,
data=ex.data,
)
else:
return SpeckleException(
message=f"Failed to execute the GraphQL {self.name} request. Inner exception: {ex}",
message=(
f"Failed to execute the GraphQL {self.name} request. Inner"
f" exception: {ex}"
),
exception=ex,
)
@@ -90,16 +96,20 @@ class ResourceBase(object):
return response
def _check_server_version_at_least(
self, target_version: Tuple[Any, ...], unsupported_message: str = None
self, target_version: Tuple[Any, ...], unsupported_message: Optional[str] = None
):
"""Use this check to guard against making unsupported requests on older servers.
Arguments:
target_version {tuple} -- the minimum server version in the format (major, minor, patch, (tag, build))
eg (2, 6, 3) for a stable build and (2, 6, 4, 'alpha', 4711) for alpha
target_version {tuple}
the minimum server version in the format (major, minor, patch, (tag, build))
eg (2, 6, 3) for a stable build and (2, 6, 4, 'alpha', 4711) for alpha
"""
if not unsupported_message:
unsupported_message = f"The client method used is not supported on Speckle Server versions prior to v{'.'.join(target_version)}"
unsupported_message = (
"The client method used is not supported on Speckle Server versions"
f" prior to v{'.'.join(target_version)}"
)
# if version is dev, it should be supported... (or not)
if self.server_version == ("dev",):
return
@@ -112,8 +122,7 @@ class ResourceBase(object):
"""
self._check_server_version_at_least(
(2, 6, 4),
(
"Stream invites are only supported as of Speckle Server v2.6.4. "
"Please update your Speckle Server to use this method or use the `grant_permission` flow instead."
),
"Stream invites are only supported as of Speckle Server v2.6.4. Please"
" update your Speckle Server to use this method or use the"
" `grant_permission` flow instead.",
)
+1 -2
View File
@@ -2,8 +2,7 @@ import pkgutil
import sys
from importlib import import_module
for (_, name, _) in pkgutil.iter_modules(__path__):
for _, name, _ in pkgutil.iter_modules(__path__):
imported_module = import_module("." + name, package=__name__)
if hasattr(imported_module, "Resource"):
+36 -12
View File
@@ -25,7 +25,9 @@ class Resource(ResourceBase):
self.schema = User
def get(self) -> User:
"""Gets the profile of a user. If no id argument is provided, will return the current authenticated user's profile (as extracted from the authorization header).
"""Gets the profile of a user. If no id argument is provided,
will return the current authenticated user's profile
(as extracted from the authorization header).
Arguments:
id {str} -- the user id
@@ -88,7 +90,9 @@ class Resource(ResourceBase):
if not params["user"]:
return SpeckleException(
message="You must provide at least one field to update your user profile"
message=(
"You must provide at least one field to update your user profile"
)
)
return self.make_request(
@@ -104,24 +108,42 @@ class Resource(ResourceBase):
cursor: Optional[datetime] = None,
):
"""
Get the activity from a given stream in an Activity collection. Step into the activity `items` for the list of activity.
If no id argument is provided, will return the current authenticated user's activity (as extracted from the authorization header).
Get the activity from a given stream in an Activity collection.
Step into the activity `items` for the list of activity.
If no id argument is provided, will return the current authenticated user's
activity (as extracted from the authorization header).
Note: all timestamps arguments should be `datetime` of any tz as they will be converted to UTC ISO format strings
Note: all timestamps arguments should be `datetime` of any tz as they will be
converted to UTC ISO format strings
user_id {str} -- the id of the user to get the activity from
action_type {str} -- filter results to a single action type (eg: `commit_create` or `commit_receive`)
action_type {str} -- filter results to a single action type
(eg: `commit_create` or `commit_receive`)
limit {int} -- max number of Activity items to return
before {datetime} -- latest cutoff for activity (ie: return all activity _before_ this time)
after {datetime} -- oldest cutoff for activity (ie: return all activity _after_ this time)
before {datetime} -- latest cutoff for activity
(ie: return all activity _before_ this time)
after {datetime} -- oldest cutoff for activity
(ie: return all activity _after_ this time)
cursor {datetime} -- timestamp cursor for pagination
"""
query = gql(
"""
query UserActivity($action_type: String, $before:DateTime, $after: DateTime, $cursor: DateTime, $limit: Int){
query UserActivity(
$action_type: String,
$before:DateTime,
$after: DateTime,
$cursor: DateTime,
$limit: Int
){
activeUser {
activity(actionType: $action_type, before: $before, after: $after, cursor: $cursor, limit: $limit) {
activity(
actionType: $action_type,
before: $before,
after: $after,
cursor: $cursor,
limit: $limit
) {
totalCount
cursor
items {
@@ -161,7 +183,8 @@ class Resource(ResourceBase):
Requires Speckle Server version >= 2.6.4
Returns:
List[PendingStreamCollaborator] -- a list of pending invites for the current user
List[PendingStreamCollaborator]
-- a list of pending invites for the current user
"""
metrics.track(metrics.INVITE, self.account, {"name": "get"})
self._check_invites_supported()
@@ -207,7 +230,8 @@ class Resource(ResourceBase):
token {str} -- the token of the invite to look for (optional)
Returns:
PendingStreamCollaborator -- the invite for the given stream (or None if it isn't found)
PendingStreamCollaborator
-- the invite for the given stream (or None if it isn't found)
"""
metrics.track(metrics.INVITE, self.account, {"name": "get"})
self._check_invites_supported()
+12 -5
View File
@@ -61,21 +61,28 @@ class Resource(ResourceBase):
"""
Not advised - generally, you want to use `operations.send()`.
Create a new object on a stream. To send a base object, you can prepare it by running it through the
`BaseObjectSerializer.traverse_base()` function to get a valid (serialisable) object to send.
Create a new object on a stream.
To send a base object, you can prepare it by running it through the
`BaseObjectSerializer.traverse_base()` function to get a valid (serialisable)
object to send.
NOTE: this does not create a commit - you can create one with `SpeckleClient.commit.create`. Dynamic fields will be located in the 'data' dict of the received `Base` object
NOTE: this does not create a commit - you can create one with
`SpeckleClient.commit.create`.
Dynamic fields will be located in the 'data' dict of the received `Base` object
Arguments:
stream_id {str} -- the id of the stream you want to send the object to
objects {List[Dict]} -- a list of base dictionary objects (NOTE: must be json serialisable)
objects {List[Dict]}
-- a list of base dictionary objects (NOTE: must be json serialisable)
Returns:
str -- the id of the object
"""
query = gql(
"""
mutation ObjectCreate($object_input: ObjectCreateInput!) { objectCreate(objectInput: $object_input) }
mutation ObjectCreate($object_input: ObjectCreateInput!) {
objectCreate(objectInput: $object_input)
}
"""
)
params = {"object_input": {"streamId": stream_id, "objects": objects}}
+27 -8
View File
@@ -58,7 +58,8 @@ class Resource(ResourceBase):
def search(
self, search_query: str, limit: int = 25
) -> Union[List[LimitedUser], SpeckleException]:
"""Searches for user by name or email. The search query must be at least 3 characters long
"""Searches for user by name or email. The search query must be at least
3 characters long
Arguments:
search_query {str} -- a string to search for
@@ -104,23 +105,41 @@ class Resource(ResourceBase):
cursor: Optional[datetime] = None,
) -> ActivityCollection:
"""
Get the activity from a given stream in an Activity collection. Step into the activity `items` for the list of activity.
Get the activity from a given stream in an Activity collection.
Step into the activity `items` for the list of activity.
Note: all timestamps arguments should be `datetime` of any tz as they will be converted to UTC ISO format strings
Note: all timestamps arguments should be `datetime` of
any tz as they will be converted to UTC ISO format strings
user_id {str} -- the id of the user to get the activity from
action_type {str} -- filter results to a single action type (eg: `commit_create` or `commit_receive`)
action_type {str} -- filter results to a single action type
(eg: `commit_create` or `commit_receive`)
limit {int} -- max number of Activity items to return
before {datetime} -- latest cutoff for activity (ie: return all activity _before_ this time)
after {datetime} -- oldest cutoff for activity (ie: return all activity _after_ this time)
before {datetime} -- latest cutoff for activity
(ie: return all activity _before_ this time)
after {datetime} -- oldest cutoff for activity
(ie: return all activity _after_ this time)
cursor {datetime} -- timestamp cursor for pagination
"""
query = gql(
"""
query UserActivity($user_id: String!, $action_type: String, $before:DateTime, $after: DateTime, $cursor: DateTime, $limit: Int){
query UserActivity(
$user_id: String!,
$action_type: String,
$before:DateTime,
$after: DateTime,
$cursor: DateTime,
$limit: Int
){
otherUser(id: $user_id) {
activity(actionType: $action_type, before: $before, after: $after, cursor: $cursor, limit: $limit) {
activity(
actionType: $action_type,
before: $before,
after: $after,
cursor: $cursor,
limit: $limit
) {
totalCount
cursor
items {
+2 -2
View File
@@ -66,8 +66,8 @@ class Resource(ResourceBase):
"""Get the server version
Returns:
tuple -- the server version in the format (major, minor, patch, (tag, build))
eg (2, 6, 3) for a stable build and (2, 6, 4, 'alpha', 4711) for alpha
the server version in the format (major, minor, patch, (tag, build))
eg (2, 6, 3) for a stable build and (2, 6, 4, 'alpha', 4711) for alpha
"""
# not tracking as it will be called along with other mutations / queries as a check
query = gql(
+16 -15
View File
@@ -1,5 +1,5 @@
from datetime import datetime, timezone
from typing import List, Optional
from typing import List
from deprecated import deprecated
from gql import gql
@@ -346,8 +346,8 @@ class Resource(ResourceBase):
@deprecated(
version="2.6.4",
reason=(
"As of Speckle Server v2.6.4, this method is deprecated. "
"Users need to be invited and accept the invite before being added to a stream"
"As of Speckle Server v2.6.4, this method is deprecated. Users need to be"
" invited and accept the invite before being added to a stream"
),
)
def grant_permission(self, stream_id: str, user_id: str, role: str):
@@ -370,11 +370,10 @@ class Resource(ResourceBase):
self.server_version == ("dev",) or self.server_version >= (2, 6, 4)
):
raise UnsupportedException(
(
"Server mutation `grant_permission` is no longer supported as of Speckle Server v2.6.4. "
"Please use the new `update_permission` method to change an existing user's permission "
"or use the `invite` method to invite a user to a stream."
)
"Server mutation `grant_permission` is no longer supported as of"
" Speckle Server v2.6.4. Please use the new `update_permission` method"
" to change an existing user's permission or use the `invite` method to"
" invite a user to a stream."
)
query = gql(
@@ -482,7 +481,8 @@ class Resource(ResourceBase):
if email is None and user_id is None:
raise SpeckleException(
"You must provide either an email or a user id to use the `stream.invite` method"
"You must provide either an email or a user id to use the"
" `stream.invite` method"
)
query = gql(
@@ -533,7 +533,8 @@ class Resource(ResourceBase):
self._check_invites_supported()
if emails is None and user_ids is None:
raise SpeckleException(
"You must provide either an email or a user id to use the `stream.invite` method"
"You must provide either an email or a user id to use the"
" `stream.invite` method"
)
query = gql(
@@ -650,10 +651,9 @@ class Resource(ResourceBase):
self.server_version != ("dev",) and self.server_version < (2, 6, 4)
):
raise UnsupportedException(
(
"Server mutation `update_permission` is only supported as of Speckle Server v2.6.4. "
"Please update your Speckle Server to use this method or use the `grant_permission` method instead."
)
"Server mutation `update_permission` is only supported as of Speckle"
" Server v2.6.4. Please update your Speckle Server to use this method"
" or use the `grant_permission` method instead."
)
query = gql(
"""
@@ -764,7 +764,8 @@ class Resource(ResourceBase):
}
except AttributeError as e:
raise SpeckleException(
"Could not get stream activity - `before`, `after`, and `cursor` must be in `datetime` format if provided",
"Could not get stream activity - `before`, `after`, and `cursor` must"
" be in `datetime` format if provided",
ValueError,
) from e
+25 -13
View File
@@ -1,5 +1,5 @@
from functools import wraps
from typing import Callable, Dict, List, Union
from typing import Callable, Dict, List, Optional, Union
from gql import gql
from graphql import DocumentNode
@@ -36,11 +36,13 @@ class Resource(ResourceBase):
)
@check_wsclient
async def stream_added(self, callback: Callable = None):
"""Subscribes to new stream added event for your profile. Use this to display an up-to-date list of streams.
async def stream_added(self, callback: Optional[Callable] = None):
"""Subscribes to new stream added event for your profile.
Use this to display an up-to-date list of streams.
Arguments:
callback {Callable[Stream]} -- a function that takes the updated stream as an argument and executes each time a stream is added
callback {Callable[Stream]} -- a function that takes the updated stream
as an argument and executes each time a stream is added
Returns:
Stream -- the update stream
@@ -55,12 +57,16 @@ class Resource(ResourceBase):
)
@check_wsclient
async def stream_updated(self, id: str, callback: Callable = None):
"""Subscribes to stream updated event. Use this in clients/components that pertain only to this stream.
async def stream_updated(self, id: str, callback: Optional[Callable] = None):
"""
Subscribes to stream updated event.
Use this in clients/components that pertain only to this stream.
Arguments:
id {str} -- the stream id of the stream to subscribe to
callback {Callable[Stream]} -- a function that takes the updated stream as an argument and executes each time the stream is updated
callback {Callable[Stream]}
-- a function that takes the updated stream
as an argument and executes each time the stream is updated
Returns:
Stream -- the update stream
@@ -81,11 +87,17 @@ class Resource(ResourceBase):
)
@check_wsclient
async def stream_removed(self, callback: Callable = None):
"""Subscribes to stream removed event for your profile. Use this to display an up-to-date list of streams for your profile. NOTE: If someone revokes your permissions on a stream, this subscription will be triggered with an extra value of revokedBy in the payload.
async def stream_removed(self, callback: Optional[Callable] = None):
"""Subscribes to stream removed event for your profile.
Use this to display an up-to-date list of streams for your profile.
NOTE: If someone revokes your permissions on a stream,
this subscription will be triggered with an extra value of revokedBy
in the payload.
Arguments:
callback {Callable[Dict]} -- a function that takes the returned dict as an argument and executes each time a stream is removed
callback {Callable[Dict]}
-- a function that takes the returned dict as an argument
and executes each time a stream is removed
Returns:
dict -- dict containing 'id' of stream removed and optionally 'revokedBy'
@@ -107,9 +119,9 @@ class Resource(ResourceBase):
async def subscribe(
self,
query: DocumentNode,
params: Dict = None,
callback: Callable = None,
return_type: Union[str, List] = None,
params: Optional[Dict] = None,
callback: Optional[Callable] = None,
return_type: Optional[Union[str, List]] = None,
schema=None,
parse_response: bool = True,
):
+7 -2
View File
@@ -12,7 +12,10 @@ from specklepy.logging.exceptions import SpeckleException
NAME = "user"
DEPRECATION_VERSION = "2.9.0"
DEPRECATION_TEXT = "The user resource is deprecated, please use the active_user or other_user resources"
DEPRECATION_TEXT = (
"The user resource is deprecated, please use the active_user or other_user"
" resources"
)
class Resource(ResourceBase):
@@ -137,7 +140,9 @@ class Resource(ResourceBase):
if not params["user"]:
return SpeckleException(
message="You must provide at least one field to update your user profile"
message=(
"You must provide at least one field to update your user profile"
)
)
return self.make_request(
+32 -15
View File
@@ -14,11 +14,15 @@ from specklepy.transports.server.server import ServerTransport
class StreamWrapper:
"""
The `StreamWrapper` gives you some handy helpers to deal with urls and get authenticated clients and transports.
The `StreamWrapper` gives you some handy helpers to deal with urls and
get authenticated clients and transports.
Construct a `StreamWrapper` with a stream, branch, commit, or object URL. The corresponding ids will be stored
in the wrapper. If you have local accounts on the machine, you can use the `get_account` and `get_client` methods
to get a local account for the server. You can also pass a token into `get_client` if you don't have a corresponding
Construct a `StreamWrapper` with a stream, branch, commit, or object URL.
The corresponding ids will be stored
in the wrapper. If you have local accounts on the machine,
you can use the `get_account` and `get_client` methods
to get a local account for the server. You can also pass a token into `get_client`
if you don't have a corresponding
local account for the server.
```py
@@ -46,7 +50,10 @@ class StreamWrapper:
_account: Account = None
def __repr__(self):
return f"StreamWrapper( server: {self.host}, stream_id: {self.stream_id}, type: {self.type} )"
return (
f"StreamWrapper( server: {self.host}, stream_id: {self.stream_id}, type:"
f" {self.type} )"
)
def __str__(self) -> str:
return self.__repr__()
@@ -72,7 +79,8 @@ class StreamWrapper:
if not segments or len(segments) < 2:
raise SpeckleException(
f"Cannot parse {url} into a stream wrapper class - invalid URL provided."
f"Cannot parse {url} into a stream wrapper class - invalid URL"
" provided."
)
while segments:
@@ -91,7 +99,8 @@ class StreamWrapper:
self.commit_id = segments.pop(0)
else:
raise SpeckleException(
f"Cannot parse {url} into a stream wrapper class - invalid URL provided."
f"Cannot parse {url} into a stream wrapper class - invalid URL"
" provided."
)
if not self.stream_id:
@@ -105,7 +114,8 @@ class StreamWrapper:
def get_account(self, token: str = None) -> Account:
"""
Gets an account object for this server from the local accounts db (added via Speckle Manager or a json file)
Gets an account object for this server from the local accounts db
(added via Speckle Manager or a json file)
"""
if self._account and self._account.token:
return self._account
@@ -129,14 +139,18 @@ class StreamWrapper:
def get_client(self, token: str = None) -> SpeckleClient:
"""
Gets an authenticated client for this server. You may provide a token if there aren't any local accounts on this
machine. If no account is found and no token is provided, an unauthenticated client is returned.
Gets an authenticated client for this server.
You may provide a token if there aren't any local accounts on this
machine. If no account is found and no token is provided,
an unauthenticated client is returned.
Arguments:
token {str} -- optional token if no local account is available (defaults to None)
token {str}
-- optional token if no local account is available (defaults to None)
Returns:
SpeckleClient -- authenticated with a corresponding local account or the provided token
SpeckleClient
-- authenticated with a corresponding local account or the provided token
"""
if self._client and token is None:
return self._client
@@ -160,11 +174,14 @@ class StreamWrapper:
def get_transport(self, token: str = None) -> ServerTransport:
"""
Gets a server transport for this stream using an authenticated client. If there is no local account for this
server and the client was not authenticated with a token, this will throw an exception.
Gets a server transport for this stream using an authenticated client.
If there is no local account for this
server and the client was not authenticated with a token,
this will throw an exception.
Returns:
ServerTransport -- constructed for this stream with a pre-authenticated client
ServerTransport -- constructed for this stream
with a pre-authenticated client
"""
if not self._account or not self._account.token:
self.get_account(token)
+8 -3
View File
@@ -13,9 +13,11 @@ class SpeckleException(Exception):
class SpeckleInvalidUnitException(SpeckleException):
def __init__(self, invalid_unit: Any) -> None:
super().__init__(
message=f"Invalid units: expected type str but received {type(invalid_unit)} ({invalid_unit}).",
message=(
"Invalid units: expected type str but received"
f" {type(invalid_unit)} ({invalid_unit})."
),
exception=None,
)
@@ -27,7 +29,10 @@ class SerializationException(SpeckleException):
self.unhandled_type = type(obj)
def __str__(self) -> str:
return f"SpeckleException: Could not serialize object of type {self.unhandled_type}"
return (
"SpeckleException: Could not serialize object of type"
f" {self.unhandled_type}"
)
class GraphQLException(SpeckleException):
+6 -2
View File
@@ -58,7 +58,11 @@ def set_host_app(host_app: str, host_app_version: Optional[str] = None):
HOST_APP_VERSION = host_app_version or HOST_APP_VERSION
def track(action: str, account: "Account" = None, custom_props: Optional[dict] = None):
def track(
action: str,
account: Optional["Account"] = None,
custom_props: Optional[dict] = None,
):
if not TRACK:
return
try:
@@ -84,7 +88,7 @@ def track(action: str, account: "Account" = None, custom_props: Optional[dict] =
LOG.debug(f"Error queueing metrics request: {str(ex)}")
def initialise_tracker(account: "Account" = None):
def initialise_tracker(account: Optional["Account"] = None):
global METRICS_TRACKER
if not METRICS_TRACKER:
METRICS_TRACKER = MetricsTracker()
+19 -11
View File
@@ -149,7 +149,7 @@ class _RegisteringBase:
raise ValueError(
f"The speckle_type: {speckle_type} is already registered for type: "
f"{cls._type_registry[cls.speckle_type].__name__}. "
f"Please choose a different type name."
"Please choose a different type name."
)
cls._type_registry[cls.speckle_type] = cls # type: ignore
try:
@@ -334,11 +334,14 @@ class Base(_RegisteringBase):
@classmethod
def update_forward_refs(cls) -> None:
"""
Attempts to populate the internal defined types dict for type checking sometime after defining the class.
This is already done when defining the class, but can be called again if references to undefined types were
Attempts to populate the internal defined types dict for type checking
sometime after defining the class.
This is already done when defining the class, but can be called
again if references to undefined types were
included.
See `objects.geometry` for an example of how this is used with the Brep class definitions
See `objects.geometry` for an example of how this is used with
the Brep class definitions.
"""
try:
cls._attr_types = get_type_hints(cls)
@@ -387,7 +390,8 @@ class Base(_RegisteringBase):
Mark defined attributes as chunkable for serialisation
Arguments:
kwargs {int} -- the name of the attribute as the keyword and the chunk size as the arg
kwargs {int} -- the name of the attribute as the keyword
and the chunk size as the arg
"""
chunkable = {k: v for k, v in kwargs.items() if isinstance(v, int)}
self._chunkable = dict(self._chunkable, **chunkable)
@@ -397,7 +401,7 @@ class Base(_RegisteringBase):
Mark defined attributes as detachable for serialisation
Arguments:
names {Set[str]} -- the names of the attributes to detach as a set of strings
names {Set[str]} -- the names of the attributes to detach as a set of string
"""
self._detachable = self._detachable.union(names)
@@ -409,7 +413,7 @@ class Base(_RegisteringBase):
@units.setter
def units(self, value: Union[str, Units, None]):
if value == None:
if value is None:
units = value
elif isinstance(value, Units):
units: Units = value
@@ -448,13 +452,17 @@ class Base(_RegisteringBase):
def get_id(self, decompose: bool = False) -> str:
"""
Gets the id (a unique hash) of this object. This method fully serializes the object which,
in the case of large objects (with many sub-objects), has a tangible cost. Avoid using it!
Gets the id (a unique hash) of this object.
This method fully serializes the object which,
in the case of large objects (with many sub-objects), has a tangible cost.
Avoid using it!
Note: the hash of a decomposed object differs from that of a non-decomposed object
Note: the hash of a decomposed object differs from that of a
non-decomposed object
Arguments:
decompose {bool} -- if True, will decompose the object in the process of hashing it
decompose {bool} -- if True, will decompose the object in
the process of hashing it
Returns:
str -- the hash (id) of the fully serialized object
+9 -3
View File
@@ -1,4 +1,4 @@
from enum import Enum, IntEnum, auto
from enum import Enum
from typing import Any, List, Optional
from specklepy.objects.base import Base
@@ -15,11 +15,17 @@ class Point(Base, speckle_type=GEOMETRY + "Point"):
z: float = 0.0
def __repr__(self) -> str:
return f"{self.__class__.__name__}(x: {self.x}, y: {self.y}, z: {self.z}, id: {self.id}, speckle_type: {self.speckle_type})"
return (
f"{self.__class__.__name__}(x: {self.x}, y: {self.y}, z: {self.z}, id:"
f" {self.id}, speckle_type: {self.speckle_type})"
)
@classmethod
def from_list(cls, args: List[float]) -> "Point":
"""Create a new Point from a list of three floats representing the x, y, and z coordinates"""
"""
Create a new Point from a list of three floats
representing the x, y, and z coordinates
"""
return cls(x=args[0], y=args[1], z=args[2])
def to_list(self) -> List[Any]:
+15 -8
View File
@@ -77,7 +77,8 @@ class Transform(
"""The 4x4 transformation matrix
The 3x3 sub-matrix determines scaling.
The 4th column defines translation, where the last value is a divisor (usually equal to 1).
The 4th column defines translation,
where the last value is a divisor (usually equal to 1).
"""
_value: Optional[List[float]] = None
@@ -93,12 +94,14 @@ class Transform(
value = [float(x) for x in value]
except (ValueError, TypeError) as error:
raise ValueError(
f"Could not create a Transform object with the requested value. Input must be a 16 element list of numbers. Value provided: {value}"
"Could not create a Transform object with the requested value. Input"
f" must be a 16 element list of numbers. Value provided: {value}"
) from error
if len(value) != 16:
raise ValueError(
f"Could not create a Transform object: input list should be 16 floats long, but was {len(value)} long"
"Could not create a Transform object: input list should be 16 floats"
f" long, but was {len(value)} long"
)
self._value = value
@@ -163,14 +166,16 @@ class Transform(
"""Transform a list of speckle Points
Arguments:
points {List[float]} -- a flat list of floats representing points to transform
points {List[float]}
-- a flat list of floats representing points to transform
Returns:
List[float] -- a new transformed list
"""
if len(points_value) % 3 != 0:
raise ValueError(
"Cannot apply transform as the points list is malformed: expected length to be multiple of 3"
"Cannot apply transform as the points list is malformed: expected"
" length to be multiple of 3"
)
transformed = []
for i in range(0, len(points_value), 3):
@@ -207,11 +212,13 @@ class Transform(
][:3]
@classmethod
def from_list(cls, value: List[float] = None) -> "Transform":
"""Returns a Transform object from a list of 16 numbers. If no value is provided, an identity transform will be returned.
def from_list(cls, value: Optional[List[float]] = None) -> "Transform":
"""Returns a Transform object from a list of 16 numbers.
If no value is provided, an identity transform will be returned.
Arguments:
value {List[float]} -- the matrix as a flat list of 16 numbers (defaults to the identity transform)
value {List[float]} -- the matrix as a flat list of 16 numbers
(defaults to the identity transform)
Returns:
Transform -- a complete transform object
@@ -9,7 +9,6 @@ STRUCTURAL_LOADING = "Objects.Structural.Loading."
class LoadType(int, Enum):
none = 0
Dead = 1
SuperDead = 2
@@ -32,7 +31,6 @@ class LoadType(int, Enum):
class ActionType(int, Enum):
none = 0
Permanent = 1
Variable = 2
@@ -40,7 +38,6 @@ class ActionType(int, Enum):
class BeamLoadType(int, Enum):
Point = 0
Uniform = 1
Linear = 2
@@ -49,21 +46,18 @@ class BeamLoadType(int, Enum):
class FaceLoadType(int, Enum):
Constant = 0
Variable = 1
Point = 2
class LoadDirection2D(int, Enum):
X = 0
Y = 1
Z = 2
class LoadDirection(int, Enum):
X = 0
Y = 1
Z = 2
@@ -81,7 +75,6 @@ class LoadAxisType(int, Enum):
class CombinationType(int, Enum):
LinearAdd = 0
Envelope = 1
AbsoluteAdd = 2
@@ -38,7 +38,6 @@ class ReferenceSurface(int, Enum):
class PropertyType2D(int, Enum):
Stress = 0
Fabric = 1
Plate = 2
@@ -2,15 +2,13 @@ import hashlib
import re
import warnings
from enum import Enum
from typing import Any, Dict, List, Tuple
from typing import Any, Dict, List, Optional, Tuple
from uuid import uuid4
from warnings import warn
import ujson
# import for serialization
import specklepy.objects.geometry
import specklepy.objects.other
from specklepy.logging.exceptions import SpeckleException, SpeckleWarning
from specklepy.objects.base import Base, DataChunk
from specklepy.transports.abstract_transport import AbstractTransport
@@ -29,7 +27,8 @@ def safe_json_loads(obj: str, obj_id=None) -> Any:
import json
warn(
f"Failed to deserialise object (id: {obj_id}). This is likely a ujson big int error - falling back to json. \nError: {err}",
f"Failed to deserialise object (id: {obj_id}). This is likely a ujson big"
f" int error - falling back to json. \nError: {err}",
SpeckleWarning,
)
return json.loads(obj)
@@ -47,7 +46,9 @@ class BaseObjectSerializer:
] # holds deserialized objects so objects with same id return the same instance
def __init__(
self, write_transports: List[AbstractTransport] = None, read_transport=None
self,
write_transports: Optional[List[AbstractTransport]] = None,
read_transport: Optional[AbstractTransport] = None,
) -> None:
self.write_transports = write_transports or []
self.read_transport = read_transport
@@ -63,7 +64,8 @@ class BaseObjectSerializer:
base {Base} -- the base object to be decomposed and serialized
Returns:
(str, str) -- a tuple containing the object id of the base object and the serialized object string
(str, str) -- a tuple containing the object id of the base object and
the serialized object string
"""
obj_id, obj = self.traverse_base(base)
@@ -77,7 +79,8 @@ class BaseObjectSerializer:
base {Base} -- the base object to be decomposed and serialized
Returns:
(str, dict) -- a tuple containing the object id of the base object and the constructed serializable dictionary
(str, dict) -- a tuple containing the object id of the base object and
the constructed serializable dictionary
"""
self.__reset_writer()
@@ -247,16 +250,19 @@ class BaseObjectSerializer:
else:
try:
return obj.dict()
except:
except Exception:
warn(
f"Failed to handle {type(obj)} in `BaseObjectSerializer.traverse_value`",
f"Failed to handle {type(obj)} in"
" `BaseObjectSerializer.traverse_value`",
SpeckleWarning,
)
return str(obj)
def detach_helper(self, ref_id: str) -> Dict[str, str]:
"""Helper to keep track of detached objects and their depth in the family tree and create reference objects to place in the parent object
"""
Helper to keep track of detached objects and their depth in the family tree
and create reference objects to place in the parent object
Arguments:
ref_id {str} -- the id of the fully traversed object
@@ -279,7 +285,10 @@ class BaseObjectSerializer:
}
def __reset_writer(self) -> None:
"""Reinitializes the lineage, and other variables that get used during the json writing process"""
"""
Reinitializes the lineage, and other variables that get used during the json
writing process
"""
self.detach_lineage = [True]
self.lineage = []
self.family_tree = {}
@@ -356,7 +365,8 @@ class BaseObjectSerializer:
base.__setattr__(prop, self.recompose_base(obj=ref_obj))
else:
warnings.warn(
f"Could not find the referenced child object of id `{ref_id}` in the given read transport: {self.read_transport.name}",
f"Could not find the referenced child object of id `{ref_id}`"
f" in the given read transport: {self.read_transport.name}",
SpeckleWarning,
)
base.__setattr__(prop, self.handle_value(value))
@@ -371,7 +381,8 @@ class BaseObjectSerializer:
return base
def handle_value(self, obj: Any):
"""Helper for recomposing a base object by handling the dictionary representation's values
"""Helper for recomposing a base object by handling the dictionary
representation's values
Arguments:
obj {Any} -- a value from the base object dictionary
@@ -417,7 +428,8 @@ class BaseObjectSerializer:
ref_obj_str = self.read_transport.get_object(id=ref_id)
if not ref_obj_str:
warnings.warn(
f"Could not find the referenced child object of id `{ref_id}` in the given read transport: {self.read_transport.name}",
f"Could not find the referenced child object of id `{ref_id}` in the"
f" given read transport: {self.read_transport.name}",
SpeckleWarning,
)
return obj
+1 -1
View File
@@ -1 +1 @@
from .server import ServerTransport
from specklepy.transports.server.server import ServerTransport
@@ -108,7 +108,8 @@ class BatchSender(object):
if not new_objects:
LOG.info(
f"Uploading batch of {len(batch)} objects: all objects are already in the server"
f"Uploading batch of {len(batch)} objects: all objects are already in"
" the server"
)
return
@@ -127,11 +128,16 @@ class BatchSender(object):
if r.status_code != 201:
LOG.warning("Upload server response: %s", r.text)
raise SpeckleException(
message=f"Could not save the object to the server - status code {r.status_code}"
message=(
"Could not save the object to the server - status code"
f" {r.status_code}"
)
)
except json.JSONDecodeError as error:
return SpeckleException(
f"Failed to send objects to {self.server_url}. Please ensure this stream ({self.stream_id}) exists on this server and that you have permission to send to it.",
f"Failed to send objects to {self.server_url}. Please ensure this"
f" stream ({self.stream_id}) exists on this server and that you have"
" permission to send to it.",
error,
)
+25 -19
View File
@@ -1,5 +1,5 @@
import json
from typing import Any, Dict, List
from typing import Any, Dict, List, Optional
from warnings import warn
import requests
@@ -14,10 +14,10 @@ from .batch_sender import BatchSender
class ServerTransport(AbstractTransport):
"""
The `ServerTransport` is the vehicle through which you transport objects to and from a Speckle Server. Provide it to
`operations.send()` or `operations.receive()`.
The `ServerTransport` is the vehicle through which you transport objects to and
from a Speckle Server. Provide it to `operations.send()` or `operations.receive()`.
The `ServerTransport` can be authenticted two different ways:
The `ServerTransport` can be authenticated two different ways:
1. by providing a `SpeckleClient`
2. by providing an `Account`
3. by providing a `token` and `url`
@@ -29,14 +29,15 @@ class ServerTransport(AbstractTransport):
# here's the data you want to send
block = Block(length=2, height=4)
# next create the server transport - this is the vehicle through which you will send and receive
# next create the server transport - this is the vehicle through which
# you will send and receive
transport = ServerTransport(stream_id=new_stream_id, client=client)
# this serialises the block and sends it to the transport
hash = operations.send(base=block, transports=[transport])
# you can now create a commit on your stream with this object
commid_id = client.commit.create(
commit_id = client.commit.create(
stream_id=new_stream_id,
obj_id=hash,
message="this is a block I made in speckle-py",
@@ -45,25 +46,26 @@ class ServerTransport(AbstractTransport):
"""
_name = "RemoteTransport"
url: str = None
stream_id: str = None
account: Account = None
url: Optional[str] = None
stream_id: Optional[str] = None
account: Optional[Account] = None
saved_obj_count: int = 0
session: requests.Session = None
session: Optional[requests.Session] = None
def __init__(
self,
stream_id: str,
client: SpeckleClient = None,
account: Account = None,
token: str = None,
url: str = None,
client: Optional[SpeckleClient] = None,
account: Optional[Account] = None,
token: Optional[str] = None,
url: Optional[str] = None,
**data: Any,
) -> None:
super().__init__(**data)
if client is None and account is None and token is None and url is None:
raise SpeckleException(
"You must provide either a client or a token and url to construct a ServerTransport."
"You must provide either a client or a token and url to construct a"
" ServerTransport."
)
if account:
@@ -74,7 +76,8 @@ class ServerTransport(AbstractTransport):
if not client.account.token:
warn(
SpeckleWarning(
f"Unauthenticated Speckle Client provided to Server Transport for {self.url}. Receiving from private streams will fail."
"Unauthenticated Speckle Client provided to Server Transport"
f" for {self.url}. Receiving from private streams will fail."
)
)
else:
@@ -118,8 +121,10 @@ class ServerTransport(AbstractTransport):
# return obj
raise SpeckleException(
"Getting a single object using `ServerTransport.get_object()` is not implemented. To get an object from the server, please use the `SpeckleClient.object.get()` route",
NotImplementedError,
"Getting a single object using `ServerTransport.get_object()` is not"
" implemented. To get an object from the server, please use the"
" `SpeckleClient.object.get()` route",
NotImplementedError(),
)
def has_objects(self, id_list: List[str]) -> Dict[str, bool]:
@@ -134,7 +139,8 @@ class ServerTransport(AbstractTransport):
if r.status_code != 200:
raise SpeckleException(
f"Can't get object {self.stream_id}/{id}: HTTP error {r.status_code} ({r.text[:1000]})"
f"Can't get object {self.stream_id}/{id}: HTTP error"
f" {r.status_code} ({r.text[:1000]})"
)
root_obj_serialized = r.text
root_obj = json.loads(root_obj_serialized)
+20 -12
View File
@@ -10,21 +10,21 @@ from specklepy.transports.abstract_transport import AbstractTransport
class SQLiteTransport(AbstractTransport):
_name = "SQLite"
_base_path: str = None
_root_path: str = None
__connection: sqlite3.Connection = None
_base_path: Optional[str] = None
_root_path: Optional[str] = None
__connection: Optional[sqlite3.Connection] = None
app_name: str = ""
scope: str = ""
saved_obj_count: int = 0
max_size: int = None
_current_batch: List[Tuple[str, str]] = None
_current_batch_size: int = None
max_size: Optional[int] = None
_current_batch: Optional[List[Tuple[str, str]]] = None
_current_batch_size: Optional[int] = None
def __init__(
self,
base_path: Optional[str] = None,
app_name: Optional[str] = None,
scope: str = None,
scope: Optional[str] = None,
max_batch_size_mb: float = 10.0,
**data: Any,
) -> None:
@@ -45,7 +45,9 @@ class SQLiteTransport(AbstractTransport):
self.__initialise()
except Exception as ex:
raise SpeckleException(
f"SQLiteTransport could not initialise {self.scope}.db at {self._base_path}. Either provide a different `base_path` or use an alternative transport.",
f"SQLiteTransport could not initialise {self.scope}.db at"
f" {self._base_path}. Either provide a different `base_path` or use an"
" alternative transport.",
ex,
)
@@ -79,14 +81,16 @@ class SQLiteTransport(AbstractTransport):
Arguments:
id {str} -- the object id
source_transport {AbstractTransport) -- the transport through which the object can be found
source_transport {AbstractTransport)
-- the transport through which the object can be found
"""
serialized_object = source_transport.get_object(id)
self.save_object(id, serialized_object)
def save_object(self, id: str, serialized_object: str) -> None:
"""
Adds an object to the current batch to be written to the db. If the current batch is full,
Adds an object to the current batch to be written to the db.
If the current batch is full,
the batch is written to the db and the current batch is reset.
Arguments:
@@ -118,7 +122,8 @@ class SQLiteTransport(AbstractTransport):
self.__connection.commit()
except Exception as ex:
raise SpeckleException(
f"Could not save the batch of objects to the local db. Inner exception: {ex}",
"Could not save the batch of objects to the local db. Inner exception:"
f" {ex}",
ex,
)
@@ -157,7 +162,10 @@ class SQLiteTransport(AbstractTransport):
raise NotImplementedError
def get_all_objects(self):
"""Returns all the objects in the store. NOTE: do not use for large collections!"""
"""
Returns all the objects in the store.
NOTE: do not use for large collections!
"""
self.__check_connection()
with closing(self.__connection.cursor()) as c:
rows = c.execute("SELECT * FROM objects").fetchall()
+6 -6
View File
@@ -13,11 +13,11 @@ from specklepy.objects.units import Units
@pytest.mark.parametrize(
"invalid_prop_name",
[
(""),
("@"),
("@@wow"),
("this.is.bad"),
("super/bad"),
"",
"@",
"@@wow",
"this.is.bad",
"super/bad",
],
)
def test_empty_prop_names(invalid_prop_name: str) -> None:
@@ -95,7 +95,7 @@ def test_setting_units():
assert b.units == "ft"
b.units = None # None should be a valid arg
assert b.units == None
assert b.units is None
b.units = Units.none
assert b.units == "none"
+1 -1
View File
@@ -85,4 +85,4 @@ class TestCommit:
message="testing received",
)
assert commit_marked_received == True
assert commit_marked_received is True
+1 -2
View File
@@ -517,8 +517,7 @@ def test_mesh_create():
mesh = Mesh.create(vertices, faces)
with pytest.raises(SpeckleException):
# pylint: disable=unused-variable
bad_mesh = Mesh.create(vertices=7, faces=faces)
bad_mesh = Mesh.create(vertices=7, faces=faces) # noqa: F841
assert mesh.vertices == vertices
assert mesh.textureCoordinates == []
-1
View File
@@ -2,7 +2,6 @@ import pytest
from specklepy.api.client import SpeckleClient
from specklepy.api.models import Activity, ActivityCollection, LimitedUser
from specklepy.logging.exceptions import SpeckleException
@pytest.mark.run(order=4)
-1
View File
@@ -6,7 +6,6 @@ from specklepy.api import operations
from specklepy.objects import Base
from specklepy.objects.fakemesh import FakeMesh
from specklepy.objects.geometry import Point
from specklepy.serialization.base_object_serializer import BaseObjectSerializer
from specklepy.transports.memory import MemoryTransport
from specklepy.transports.server import ServerTransport
-2
View File
@@ -1,5 +1,3 @@
from datetime import datetime
import pytest
from specklepy.api.client import SpeckleClient
+2 -7
View File
@@ -4,12 +4,7 @@ import pytest
from specklepy.api import operations
from specklepy.objects.geometry import Point, Vector
from specklepy.objects.other import (
IDENTITY_TRANSFORM,
BlockDefinition,
BlockInstance,
Transform,
)
from specklepy.objects.other import Transform
@pytest.fixture()
@@ -81,7 +76,7 @@ def test_point_transform(point: Point, transform: Transform):
def test_points_transform(points: List[Point], transform: Transform):
new_points = transform.apply_to_points(points)
for (i, new_point) in enumerate(new_points):
for i, new_point in enumerate(new_points):
assert new_point.x == points[i].x + 1
assert new_point.y == points[i].y + 2
assert new_point.z == points[i].z * 0.5
+6 -5
View File
@@ -1,11 +1,11 @@
import json
from pathlib import Path
from typing import Generator, Iterable
import pytest
from specklepy.api.wrapper import StreamWrapper
from specklepy.paths import accounts_path
from specklepy.transports.sqlite import SQLiteTransport
def test_parse_stream():
@@ -60,7 +60,8 @@ def test_parse_globals_as_commit():
assert wrap.type == "commit"
#! NOTE: the following three tests may not pass locally if you have a `speckle.xyz` account in manager
#! NOTE: the following three tests may not pass locally
# if you have a `speckle.xyz` account in manager
def test_get_client_without_auth():
wrap = StreamWrapper("https://speckle.xyz/streams/4c3ce1459c/commits/8b9b831792")
client = wrap.get_client()
@@ -88,16 +89,16 @@ def test_get_transport_with_token():
@pytest.fixture
def user_path() -> Path:
def user_path() -> Iterable[Path]:
path = accounts_path().joinpath("test_acc.json")
# hey, py37 doesn't support the missing_ok argument
try:
path.unlink()
except:
except Exception:
pass
try:
path.unlink(missing_ok=True)
except:
except Exception:
pass
path.parent.absolute().mkdir(exist_ok=True)
yield path