diff --git a/patch_version.py b/patch_version.py index 1c7262c..bbeef65 100644 --- a/patch_version.py +++ b/patch_version.py @@ -5,7 +5,7 @@ import sys def patch(tag): print(f"Patching version: {tag}") - with open("pyproject.toml", "r") as f: + with open("pyproject.toml") as f: lines = f.readlines() if "version" not in lines[2]: diff --git a/src/speckle_automate/automation_context.py b/src/speckle_automate/automation_context.py index 58aec7d..7bdac2c 100644 --- a/src/speckle_automate/automation_context.py +++ b/src/speckle_automate/automation_context.py @@ -96,7 +96,8 @@ class AutomationContext: def receive_version(self) -> Base: """Receive the Speckle project version that triggered this automation run.""" - # TODO: this is a quick hack to keep implementation consistency. Move to proper receive many versions + # TODO: this is a quick hack to keep implementation consistency. + # Move to proper receive many versions version_id = self.automation_run_data.triggers[0].payload.version_id commit = self.speckle_client.commit.get( self.automation_run_data.project_id, version_id @@ -264,7 +265,8 @@ class AutomationContext: if not path_obj.exists(): raise ValueError("The given file path doesn't exist") - files = {path_obj.name: open(str(path_obj), "rb")} + + files = {path_obj.name: path_obj.open("rb")} url = ( f"{self.automation_run_data.speckle_server_url}api/stream/" diff --git a/src/speckle_automate/runner.py b/src/speckle_automate/runner.py index dcac239..7334395 100644 --- a/src/speckle_automate/runner.py +++ b/src/speckle_automate/runner.py @@ -128,7 +128,8 @@ def execute_automate_function( automate_function, # type: ignore ) - # if we've gotten this far, the execution should technically be completed as expected + # if we've gotten this far, + # the execution should technically be completed as expected # thus exiting with 0 is the schemantically correct thing to do exit_code = ( 1 if automation_context.run_status == AutomationStatus.EXCEPTION else 0 @@ -190,4 +191,4 @@ def run_function( if not automation_context.context_view: automation_context.set_context_view() automation_context.report_run_status() - return automation_context + return automation_context diff --git a/src/specklepy/api/client.py b/src/specklepy/api/client.py index af6d01d..4a1ba92 100644 --- a/src/specklepy/api/client.py +++ b/src/specklepy/api/client.py @@ -1,3 +1,5 @@ +import contextlib + from deprecated import deprecated from specklepy.api.credentials import Account @@ -40,7 +42,8 @@ class SpeckleClient(CoreSpeckleClient): client = SpeckleClient(host="app.speckle.systems") # or whatever your host is # client = SpeckleClient(host="localhost:3000", use_ssl=False) or use local server - # authenticate the client with an account (account has been added in Speckle Manager) + # authenticate the client with an account + # (account has been added in Speckle Manager) account = get_default_account() client.authenticate_with_account(account) @@ -74,10 +77,9 @@ class SpeckleClient(CoreSpeckleClient): ) server_version = None - try: + + with contextlib.suppress(Exception): server_version = self.server.version() - except Exception: - pass self.other_user = OtherUserResource( account=self.account, diff --git a/src/specklepy/api/operations.py b/src/specklepy/api/operations.py index 4f7cb1e..86b9f58 100644 --- a/src/specklepy/api/operations.py +++ b/src/specklepy/api/operations.py @@ -53,7 +53,9 @@ def receive( return _untracked_receive(obj_id, remote_transport, local_transport) -def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str: +def serialize( + base: Base, write_transports: List[AbstractTransport] | None = None +) -> str: """ Serialize a base object. If no write transports are provided, the object will be serialized @@ -67,6 +69,8 @@ def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str Returns: str -- the serialized object """ + if not write_transports: + write_transports = [] metrics.track(metrics.SDK, custom_props={"name": "Serialize"}) return core_serialize(base, write_transports) diff --git a/src/specklepy/api/resources/current/other_user_resource.py b/src/specklepy/api/resources/current/other_user_resource.py index 141ffb5..dec00d1 100644 --- a/src/specklepy/api/resources/current/other_user_resource.py +++ b/src/specklepy/api/resources/current/other_user_resource.py @@ -19,8 +19,10 @@ from specklepy.logging.exceptions import SpeckleException class OtherUserResource(CoreResource): """ Provides API access to other users' profiles and activities on the platform. - This class enables fetching limited information about users, searching for users by name or email, - and accessing user activity logs with appropriate privacy and access control measures in place. + This class enables fetching limited information about users, + searching for users by name or email, + and accessing user activity logs with appropriate privacy + and access control measures in place. """ def __init__(self, account, basepath, client, server_version) -> None: @@ -63,7 +65,8 @@ class OtherUserResource(CoreResource): limit (int): Maximum number of search results to return. Returns: - Union[List[LimitedUser], SpeckleException]: A list of users matching the search + Union[List[LimitedUser], SpeckleException]: + A list of users matching the search query or an exception if the query is too short. """ if len(search_query) < 3: @@ -85,8 +88,8 @@ class OtherUserResource(CoreResource): cursor: Optional[datetime] = None, ) -> ActivityCollection: """ - Retrieves a collection of activities for a specified user, with optional filters for activity type, - time frame, and pagination. + Retrieves a collection of activities for a specified user, + with optional filters for activity type, time frame, and pagination. Args: user_id (str): The ID of the user whose activities are being requested. @@ -97,7 +100,8 @@ class OtherUserResource(CoreResource): cursor (Optional[datetime]): Timestamp for pagination cursor. Returns: - ActivityCollection: A collection of user activities filtered according to specified criteria. + ActivityCollection: A collection of user activities filtered + according to specified criteria. """ metrics.track(metrics.SDK, self.account, {"name": "Other User Activity"}) return super().activity(user_id, limit, action_type, before, after, cursor) diff --git a/src/specklepy/api/resources/current/server_resource.py b/src/specklepy/api/resources/current/server_resource.py index 85ee78e..38421f6 100644 --- a/src/specklepy/api/resources/current/server_resource.py +++ b/src/specklepy/api/resources/current/server_resource.py @@ -31,7 +31,8 @@ class ServerResource(CoreResource): 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 + # not tracking as it will be called along with other + # mutations / queries as a check return super().version() def apps(self) -> Dict: diff --git a/src/specklepy/core/api/client.py b/src/specklepy/core/api/client.py index 3c1511d..82431f0 100644 --- a/src/specklepy/core/api/client.py +++ b/src/specklepy/core/api/client.py @@ -1,3 +1,4 @@ +import contextlib import re from typing import Dict from warnings import warn @@ -49,7 +50,8 @@ class SpeckleClient: client = SpeckleClient(host="app.speckle.systems") # or whatever your host is # client = SpeckleClient(host="localhost:3000", use_ssl=False) or use local server - # authenticate the client with an account (account has been added in Speckle Manager) + # authenticate the client with an account + # (account has been added in Speckle Manager) account = get_default_account() client.authenticate_with_account(account) @@ -102,7 +104,8 @@ class SpeckleClient: self._init_resources() - # ? Check compatibility with the server - i think we can skip this at this point? save a request + # ? Check compatibility with the server + # - i think we can skip this at this point? save a request # try: # server_info = self.server.get() # if isinstance(server_info, Exception): @@ -187,9 +190,10 @@ class SpeckleClient: if ex.exception.code == 403: warn( SpeckleWarning( - "Possibly invalid token - could not authenticate Speckle Client" - f" for server {self.url}" - ) + "Possibly invalid token - could not authenticate " + f"Speckle Client for server {self.url}" + ), + stacklevel=2, ) else: raise ex @@ -203,10 +207,8 @@ class SpeckleClient: ) server_version = None - try: + with contextlib.suppress(Exception): server_version = self.server.version() - except Exception: - pass self.other_user = OtherUserResource( account=self.account, @@ -283,7 +285,7 @@ class SpeckleClient: return attr.Resource( account=self.account, basepath=self.url, client=self.httpclient ) - except AttributeError: + except AttributeError as ex: raise SpeckleException( f"Method {name} is not supported by the SpeckleClient class" - ) + ) from ex diff --git a/src/specklepy/core/api/models/current.py b/src/specklepy/core/api/models/current.py index 549c4c4..4826c46 100644 --- a/src/specklepy/core/api/models/current.py +++ b/src/specklepy/core/api/models/current.py @@ -55,7 +55,8 @@ class ServerConfiguration(BaseModel): objectSizeLimitBytes: int -# Keeping this one all Optionals at the minute, because its used both as a deserialization model for GQL and Account Management +# Keeping this one all Optionals at the minute, +# because its used both as a deserialization model for GQL and Account Management class ServerInfo(BaseModel): name: Optional[str] = None company: Optional[str] = None diff --git a/src/specklepy/core/api/models/deprecated.py b/src/specklepy/core/api/models/deprecated.py index 1ea17fc..32d34a4 100644 --- a/src/specklepy/core/api/models/deprecated.py +++ b/src/specklepy/core/api/models/deprecated.py @@ -4,7 +4,10 @@ from typing import List, Optional from deprecated import deprecated from pydantic import BaseModel, Field -FE1_DEPRECATION_REASON = "Stream/Branch/Commit API is now deprecated, Use the new Project/Model/Version API functions in Client}" +FE1_DEPRECATION_REASON = ( + "Stream/Branch/Commit API is now deprecated, " + "Use the new Project/Model/Version API functions in Client" +) FE1_DEPRECATION_VERSION = "2.20" diff --git a/src/specklepy/core/api/operations.py b/src/specklepy/core/api/operations.py index 9d5d4c8..77989fe 100644 --- a/src/specklepy/core/api/operations.py +++ b/src/specklepy/core/api/operations.py @@ -70,7 +70,8 @@ def receive( serializer = BaseObjectSerializer(read_transport=local_transport) - # try local transport first. if the parent is there, we assume all the children are there and continue with deserialization using the local transport + # try local transport first. if the parent is there, we assume all the children + # are there and continue with deserialization using the local transport obj_string = local_transport.get_object(obj_id) if obj_string: return serializer.read_json(obj_string=obj_string) @@ -90,7 +91,7 @@ def receive( return serializer.read_json(obj_string=obj_string) -def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str: +def serialize(base: Base, write_transports: List[AbstractTransport] | None) -> str: """ Serialize a base object. If no write transports are provided, the object will be serialized @@ -104,6 +105,8 @@ def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str Returns: str -- the serialized object """ + if not write_transports: + write_transports = [] serializer = BaseObjectSerializer(write_transports=write_transports) return serializer.write_json(base)[1] diff --git a/src/specklepy/core/api/resource.py b/src/specklepy/core/api/resource.py index ad992af..089928f 100644 --- a/src/specklepy/core/api/resource.py +++ b/src/specklepy/core/api/resource.py @@ -18,7 +18,7 @@ from specklepy.transports.sqlite import SQLiteTransport T = TypeVar("T", bound=BaseModel) -class ResourceBase(object): +class ResourceBase: def __init__( self, account: Account, @@ -101,7 +101,8 @@ class ResourceBase(object): parse_response: bool = True, ) -> Any: """Executes the GraphQL query""" - # This method has quite complex and ambiguous typing, and counter-intuitive error handling + # This method has quite complex and ambiguous typing, + # and counter-intuitive error handling # We are going to phase it out in favour of `make_request_and_parse_response` try: with self.__lock: diff --git a/src/specklepy/core/api/resources/current/active_user_resource.py b/src/specklepy/core/api/resources/current/active_user_resource.py index 99d7c03..a73a0da 100644 --- a/src/specklepy/core/api/resources/current/active_user_resource.py +++ b/src/specklepy/core/api/resources/current/active_user_resource.py @@ -36,10 +36,12 @@ class ActiveUserResource(ResourceBase): self.schema = User def get(self) -> Optional[User]: - """Gets the currently active user profile (as extracted from the authorization header) + """Gets the currently active user profile + (as extracted from the authorization header) Returns: - User -- the requested user, or none if no authentication token is provided to the Client + User -- the requested user, or none if no authentication token + is provided to the Client """ QUERY = gql( """ diff --git a/src/specklepy/core/api/resources/current/model_resource.py b/src/specklepy/core/api/resources/current/model_resource.py index 9f9fcd9..93e49cd 100644 --- a/src/specklepy/core/api/resources/current/model_resource.py +++ b/src/specklepy/core/api/resources/current/model_resource.py @@ -75,14 +75,24 @@ class ModelResource(ResourceBase): ) -> ModelWithVersions: QUERY = gql( """ - query ModelGetWithVersions($modelId: String!, $projectId: String!, $versionsLimit: Int!, $versionsCursor: String, $versionsFilter: ModelVersionsFilter) { + query ModelGetWithVersions( + $modelId: String!, + $projectId: String!, + $versionsLimit: Int!, + $versionsCursor: String, + $versionsFilter: ModelVersionsFilter + ) { data:project(id: $projectId) { data:model(id: $modelId) { id name previewUrl updatedAt - versions(limit: $versionsLimit, cursor: $versionsCursor, filter: $versionsFilter) { + versions( + limit: $versionsLimit, + cursor: $versionsCursor, + filter: $versionsFilter + ) { items { id referencedObject @@ -147,9 +157,18 @@ class ModelResource(ResourceBase): ) -> ResourceCollection[Model]: QUERY = gql( """ - query ProjectGetWithModels($projectId: String!, $modelsLimit: Int!, $modelsCursor: String, $modelsFilter: ProjectModelsFilter) { + query ProjectGetWithModels( + $projectId: String!, + $modelsLimit: Int!, + $modelsCursor: String, + $modelsFilter: ProjectModelsFilter + ) { data:project(id: $projectId) { - data:models(limit: $modelsLimit, cursor: $modelsCursor, filter: $modelsFilter) { + data:models( + limit: $modelsLimit, + cursor: $modelsCursor, + filter: $modelsFilter + ) { items { id name diff --git a/src/specklepy/core/api/resources/current/other_user_resource.py b/src/specklepy/core/api/resources/current/other_user_resource.py index 49bb80f..00eb545 100644 --- a/src/specklepy/core/api/resources/current/other_user_resource.py +++ b/src/specklepy/core/api/resources/current/other_user_resource.py @@ -73,7 +73,9 @@ class OtherUserResource(ResourceBase): archived: bool = False, emailOnly: bool = False, ) -> UserSearchResultCollection: - """Searches for a user on the server, by name or email. The search query must be at least + """ + Searches for a user on the server, by name or email. + The search query must be at least 3 characters long Arguments: @@ -88,8 +90,20 @@ class OtherUserResource(ResourceBase): QUERY = gql( """ - query UserSearch($query: String!, $limit: Int!, $cursor: String, $archived: Boolean, $emailOnly: Boolean) { - data:userSearch(query: $query, limit: $limit, cursor: $cursor, archived: $archived, emailOnly: $emailOnly) { + query UserSearch( + $query: String!, + $limit: Int!, + $cursor: String, + $archived: Boolean, + $emailOnly: Boolean + ) { + data:userSearch( + query: $query, + limit: $limit, + cursor: $cursor, + archived: $archived, + emailOnly: $emailOnly + ) { cursor items { id diff --git a/src/specklepy/core/api/resources/current/project_invite_resource.py b/src/specklepy/core/api/resources/current/project_invite_resource.py index 75459a1..5c6e692 100644 --- a/src/specklepy/core/api/resources/current/project_invite_resource.py +++ b/src/specklepy/core/api/resources/current/project_invite_resource.py @@ -36,7 +36,10 @@ class ProjectInviteResource(ResourceBase): ) -> ProjectWithTeam: QUERY = gql( """ - mutation ProjectInviteCreate($projectId: ID!, $input: ProjectInviteCreateInput!) { + mutation ProjectInviteCreate( + $projectId: ID!, + $input: ProjectInviteCreateInput! + ) { data:projectMutations { data:invites { data:create(projectId: $projectId, input: $input) { diff --git a/src/specklepy/core/api/resources/current/project_resource.py b/src/specklepy/core/api/resources/current/project_resource.py index 95f5aaf..db7d025 100644 --- a/src/specklepy/core/api/resources/current/project_resource.py +++ b/src/specklepy/core/api/resources/current/project_resource.py @@ -64,7 +64,12 @@ class ProjectResource(ResourceBase): ) -> ProjectWithModels: QUERY = gql( """ - query ProjectGetWithModels($projectId: String!, $modelsLimit: Int!, $modelsCursor: String, $modelsFilter: ProjectModelsFilter) { + query ProjectGetWithModels( + $projectId: String!, + $modelsLimit: Int!, + $modelsCursor: String, + $modelsFilter: ProjectModelsFilter + ) { data:project(id: $projectId) { id name @@ -76,7 +81,11 @@ class ProjectResource(ResourceBase): updatedAt sourceApps workspaceId - models(limit: $modelsLimit, cursor: $modelsCursor, filter: $modelsFilter) { + models( + limit: $modelsLimit, + cursor: $modelsCursor, + filter: $modelsFilter + ) { items { id name diff --git a/src/specklepy/core/api/resources/current/server_resource.py b/src/specklepy/core/api/resources/current/server_resource.py index 788b120..060ae6c 100644 --- a/src/specklepy/core/api/resources/current/server_resource.py +++ b/src/specklepy/core/api/resources/current/server_resource.py @@ -79,7 +79,8 @@ class ServerResource(ResourceBase): 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 + # not tracking as it will be called along with other mutations / queries + # as a check query = gql( """ query Server { diff --git a/src/specklepy/core/api/wrapper.py b/src/specklepy/core/api/wrapper.py index b27b3ed..92cc7ef 100644 --- a/src/specklepy/core/api/wrapper.py +++ b/src/specklepy/core/api/wrapper.py @@ -159,11 +159,12 @@ class StreamWrapper: try: self.branch_name = project["project"]["model"]["name"] except KeyError as ke: - raise SpeckleException("Project model name is not found", ke) + raise SpeckleException("Project model name is not found", ke) from ke if not self.stream_id: raise SpeckleException( - f"Cannot parse {url} into a stream wrapper class - no {key_stream} id found." + f"Cannot parse {url} into a stream wrapper class - no {key_stream} ", + "id found.", ) @property @@ -213,7 +214,11 @@ class StreamWrapper: self._client = SpeckleClient(host=self.host, use_ssl=self.use_ssl) if self._account.token is None and token is None: - warn(f"No local account found for server {self.host}", SpeckleWarning) + warn( + f"No local account found for server {self.host}", + SpeckleWarning, + stacklevel=2, + ) return self._client if self._account.token: @@ -266,14 +271,20 @@ class StreamWrapper: if use_fe2 is False or (use_fe2 is True and not self.model_id): base_url = f"{self.server_url}{key_streams}{self.stream_id}" else: # fe2 is True and model_id available - base_url = f"{self.server_url}{key_streams}{self.stream_id}{key_branches}{value_branch}" + base_url = ( + f"{self.server_url}{key_streams}" + f"{self.stream_id}{key_branches}{value_branch}" + ) if wrapper_type == "object": return f"{base_url}{key_objects}{self.object_id}" elif wrapper_type == "commit": return f"{base_url}{key_commits}{self.commit_id}" elif wrapper_type == "branch": - return f"{self.server_url}{key_streams}{self.stream_id}{key_branches}{value_branch}" + return ( + f"{self.server_url}{key_streams}{self.stream_id}" + f"{key_branches}{value_branch}" + ) elif wrapper_type == "stream": return f"{self.server_url}{key_streams}{self.stream_id}" else: diff --git a/src/specklepy/core/helpers/speckle_path_provider.py b/src/specklepy/core/helpers/speckle_path_provider.py index f673421..dfa82ec 100644 --- a/src/specklepy/core/helpers/speckle_path_provider.py +++ b/src/specklepy/core/helpers/speckle_path_provider.py @@ -99,7 +99,7 @@ def user_application_data_path() -> Path: except Exception as ex: raise SpeckleException( message="Failed to initialize user application data path.", exception=ex - ) + ) from ex def user_speckle_folder_path() -> Path: diff --git a/src/specklepy/logging/metrics.py b/src/specklepy/logging/metrics.py index 3177ee7..67d684e 100644 --- a/src/specklepy/logging/metrics.py +++ b/src/specklepy/logging/metrics.py @@ -86,7 +86,8 @@ def track( METRICS_TRACKER.queue.put_nowait(event_params) except Exception as ex: - # wrapping this whole thing in a try except as we never want a failure here to annoy users! + # wrapping this whole thing in a try except as we never want a failure here + # to annoy users! LOG.debug(f"Error queueing metrics request: {str(ex)}") @@ -106,7 +107,7 @@ class Singleton(type): def __call__(cls, *args, **kwargs): if cls not in cls._instances: - cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) + cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls] diff --git a/src/specklepy/objects/base.py b/src/specklepy/objects/base.py index bfd68cd..2c7959a 100644 --- a/src/specklepy/objects/base.py +++ b/src/specklepy/objects/base.py @@ -223,7 +223,7 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]: if isinstance(t, ForwardRef): return True, value - origin = getattr(t, "__origin__") + origin = t.__origin__ # below is what in nicer for >= py38 # origin = get_origin(t) @@ -288,7 +288,7 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]: if len(args) != len(value): return False, value values = [] - for t_item, v_item in zip(args, value): + for t_item, v_item in zip(args, value, strict=True): item_valid, item_value = _validate_type(t_item, v_item) if not item_valid: return False, value @@ -371,7 +371,8 @@ class Base(_RegisteringBase, speckle_type="Base"): if name == "speckle_type": # not sure if we should raise an exception here?? # raise SpeckleException( - # "Cannot override the `speckle_type`. This is set manually by the class or on deserialisation" + # "Cannot override the `speckle_type`." + # "This is set manually by the class or on deserialisation" # ) return # if value is not None: @@ -399,7 +400,10 @@ class Base(_RegisteringBase, speckle_type="Base"): try: cls._attr_types = get_type_hints(cls) except Exception as e: - warn(f"Could not update forward refs for class {cls.__name__}: {e}") + warn( + f"Could not update forward refs for class {cls.__name__}: {e}", + stacklevel=2, + ) @classmethod def validate_prop_name(cls, name: str) -> None: @@ -464,7 +468,8 @@ class Base(_RegisteringBase, speckle_type="Base"): # @units.setter # def units(self, value: Union[str, Units, None]): - # """While this property accepts any string value, geometry expects units to be specific strings (see Units enum)""" + # """While this property accepts any string value, + # geometry expects units to be specific strings (see Units enum)""" # if isinstance(value, str) or value is None: # self._units = value # elif isinstance(value, Units): diff --git a/src/specklepy/objects/geometry.py b/src/specklepy/objects/geometry.py index 599b32e..bd47ac1 100644 --- a/src/specklepy/objects/geometry.py +++ b/src/specklepy/objects/geometry.py @@ -23,7 +23,10 @@ class Point(Base, IHasUnits, speckle_type="Objects.Geometry.Point"): z: float def __repr__(self) -> str: - return f"{self.__class__.__name__}(x: {self.x}, y: {self.y}, z: {self.z}, units: {self.units})" + return ( + f"{self.__class__.__name__}" + f"(x: {self.x}, y: {self.y}, z: {self.z}, units: {self.units})" + ) def to_list(self) -> List[float]: return [self.x, self.y, self.z] diff --git a/src/specklepy/objects/interfaces.py b/src/specklepy/objects/interfaces.py index ad91a7c..c5f9ef8 100644 --- a/src/specklepy/objects/interfaces.py +++ b/src/specklepy/objects/interfaces.py @@ -67,7 +67,7 @@ class IHasArea(metaclass=ABCMeta): @area.setter def area(self, value: float): - if not isinstance(value, (int, float)): + if not isinstance(value, int | float): raise ValueError(f"Area must be a number, got {type(value)}") self._area = float(value) @@ -83,7 +83,7 @@ class IHasVolume(metaclass=ABCMeta): @volume.setter def volume(self, value: float): - if not isinstance(value, (int, float)): + if not isinstance(value, int | float): raise ValueError(f"Volume must be a number, got {type(value)}") self._volume = float(value) diff --git a/src/specklepy/objects/models/collections/collection.py b/src/specklepy/objects/models/collections/collection.py index 97546d7..96236b8 100644 --- a/src/specklepy/objects/models/collections/collection.py +++ b/src/specklepy/objects/models/collections/collection.py @@ -12,18 +12,25 @@ class Collection( detachable={"elements"}, ): """ - A simple container for organising objects within a model and preserving object hierarchy. + A simple container for organising objects within a model + and preserving object hierarchy. - A container is defined by a human-readable name a unique applicationId and its list of contained elements. - The elements can include an unrestricted number of Base objects including additional nested Collections. + A container is defined by a human-readable name a unique applicationId and + its list of contained elements. + The elements can include an unrestricted number of Base objects including + additional nested Collections. Note: - A Collection can be for example a Layer in Rhino/AutoCad, a collection in Blender, or a Category in Revit. - The location of each collection in the hierarchy of collections in a commit will be retrieved through commit traversal. + A Collection can be for example a Layer in Rhino/AutoCad, + a collection in Blender, or a Category in Revit. + The location of each collection in the hierarchy of collections in a commit + will be retrieved through commit traversal. Attributes: - name: The human-readable name of the Collection. This name is not necessarily unique within a commit. Set the applicationId for a unique identifier. - elements: The elements contained in this Collection. This may include additional nested Collections + name: The human-readable name of the Collection. This name is not necessarily + unique within a commit. Set the applicationId for a unique identifier. + elements: The elements contained in this Collection. + This may include additional nested Collections """ name: str diff --git a/src/specklepy/objects/proxies.py b/src/specklepy/objects/proxies.py index 5eaa3fe..c47e307 100644 --- a/src/specklepy/objects/proxies.py +++ b/src/specklepy/objects/proxies.py @@ -1,4 +1,4 @@ -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import List, Optional from specklepy.objects.base import Base diff --git a/src/specklepy/objects/tests/mesh_test.py b/src/specklepy/objects/tests/mesh_test.py index 6e660a6..27a2d6c 100644 --- a/src/specklepy/objects/tests/mesh_test.py +++ b/src/specklepy/objects/tests/mesh_test.py @@ -148,7 +148,7 @@ cube_mesh = Mesh( volume=0.0, ) -print(f"\nMesh Details:") +print("\nMesh Details:") print(f"Number of vertices: {cube_mesh.vertices_count}") print(f"Number of texture coordinates: {cube_mesh.texture_coordinates_count}") diff --git a/src/specklepy/objects_v2/base.py b/src/specklepy/objects_v2/base.py index 5373b36..035ee2f 100644 --- a/src/specklepy/objects_v2/base.py +++ b/src/specklepy/objects_v2/base.py @@ -19,7 +19,7 @@ from warnings import warn from stringcase import pascalcase from specklepy.logging.exceptions import SpeckleException, SpeckleInvalidUnitException -from specklepy.objects.units import Units +from specklepy.objects_v2.units import Units from specklepy.transports.memory import MemoryTransport PRIMITIVES = (int, float, str, bool) @@ -225,7 +225,7 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]: if isinstance(t, ForwardRef): return True, value - origin = getattr(t, "__origin__") + origin = t.__origin__ # below is what in nicer for >= py38 # origin = get_origin(t) @@ -290,7 +290,7 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]: if len(args) != len(value): return False, value values = [] - for t_item, v_item in zip(args, value): + for t_item, v_item in zip(args, value, strict=True): item_valid, item_value = _validate_type(t_item, v_item) if not item_valid: return False, value @@ -387,7 +387,8 @@ class Base(_RegisteringBase, speckle_type="Base"): if name == "speckle_type": # not sure if we should raise an exception here?? # raise SpeckleException( - # "Cannot override the `speckle_type`. This is set manually by the class or on deserialisation" + # "Cannot override the `speckle_type`." + # "This is set manually by the class or on deserialisation" # ) return # if value is not None: @@ -415,7 +416,10 @@ class Base(_RegisteringBase, speckle_type="Base"): try: cls._attr_types = get_type_hints(cls) except Exception as e: - warn(f"Could not update forward refs for class {cls.__name__}: {e}") + warn( + f"Could not update forward refs for class {cls.__name__}: {e}", + stacklevel=2, + ) @classmethod def validate_prop_name(cls, name: str) -> None: @@ -480,7 +484,10 @@ class Base(_RegisteringBase, speckle_type="Base"): @units.setter def units(self, value: Union[str, Units, None]): - """While this property accepts any string value, geometry expects units to be specific strings (see Units enum)""" + """ + While this property accepts any string value, + geometry expects units to be specific strings (see Units enum) + """ if isinstance(value, str) or value is None: self._units = value elif isinstance(value, Units): diff --git a/src/specklepy/objects_v2/geometry.py b/src/specklepy/objects_v2/geometry.py index 2aaed6e..5f7f1e2 100644 --- a/src/specklepy/objects_v2/geometry.py +++ b/src/specklepy/objects_v2/geometry.py @@ -1,10 +1,10 @@ from enum import Enum from typing import Any, List, Optional -from specklepy.objects.base import Base -from specklepy.objects.encoding import CurveArray, CurveTypeEncoding, ObjectArray -from specklepy.objects.primitive import Interval -from specklepy.objects.units import get_encoding_from_units, get_units_from_encoding +from specklepy.objects_v2.base import Base +from specklepy.objects_v2.encoding import CurveArray, CurveTypeEncoding, ObjectArray +from specklepy.objects_v2.primitive import Interval +from specklepy.objects_v2.units import get_encoding_from_units, get_units_from_encoding GEOMETRY = "Objects.Geometry." @@ -918,10 +918,12 @@ class Brep( self.Vertices = vertices - # TODO: can this be consistent with loops, edges, faces, curves, etc and prepend with the chunk list? needs to happen in sharp first + # TODO: can this be consistent with loops, edges, faces, curves, + # etc and prepend with the chunk list? needs to happen in sharp first @property def TrimsValue(self) -> List[float]: - # return None if self.Trims is None else ObjectArray.from_objects(self.Trims).data + # return None if self.Trims is None else + # ObjectArray.from_objects(self.Trims).data if not self.Trims: return value = [] diff --git a/src/specklepy/objects_v2/graph_traversal/commit_object_builder.py b/src/specklepy/objects_v2/graph_traversal/commit_object_builder.py index 2247802..6c9e8e5 100644 --- a/src/specklepy/objects_v2/graph_traversal/commit_object_builder.py +++ b/src/specklepy/objects_v2/graph_traversal/commit_object_builder.py @@ -57,9 +57,7 @@ class CommitObjectBuilder(ABC, Generic[T]): if parent_id == ROOT: parent = root_commit_object else: - parent = ( - self.converted[parent_id] if parent_id in self.converted else None - ) + parent = self.converted.get(parent_id, None) if not parent: continue @@ -73,13 +71,15 @@ class CommitObjectBuilder(ABC, Generic[T]): elements.append(current) return except Exception as ex: - # A parent was found, but it was invalid (Likely because of a type mismatch on a `elements` property) + # A parent was found, but it was invalid + # (Likely because of a type mismatch on a `elements` property) print( f"Failed to add object {type(current)} to a converted parent; {ex}" ) raise Exception( - f"Could not find a valid parent for object of type {type(current)}. Checked {len(parents)} potential parent, and non were converted!" + f"Could not find a valid parent for object of type {type(current)}." + f"Checked {len(parents)} potential parent, and non were converted!" ) diff --git a/src/specklepy/objects_v2/graph_traversal/traversal.py b/src/specklepy/objects_v2/graph_traversal/traversal.py index 0428214..a3f33ee 100644 --- a/src/specklepy/objects_v2/graph_traversal/traversal.py +++ b/src/specklepy/objects_v2/graph_traversal/traversal.py @@ -57,12 +57,16 @@ class GraphTraversal: for child_prop in members_to_traverse: try: if child_prop in {"speckle_type", "units", "applicationId"}: - continue # debug: to avoid noisy exceptions, explicitly avoid checking ones we know will fail, this is not exhaustive + # debug: to avoid noisy exceptions, + # explicitly avoid checking ones we know will fail, + # this is not exhaustive + continue if getattr(current, child_prop, None): value = current[child_prop] self._traverse_member_to_stack(stack, value, child_prop, head) except KeyError: - # Unset application ids, and class variables like SpeckleType will throw when __getitem__ is called + # Unset application ids, and class variables like SpeckleType will + # throw when __getitem__ is called pass @staticmethod @@ -118,7 +122,4 @@ class TraversalRule: return set(self._members_to_traverse(o)) def does_rule_hold(self, o: Base) -> bool: - for condition in self._conditions: - if condition(o): - return True - return False + return any(condition(o) for condition in self._conditions) diff --git a/src/specklepy/serialization/base_object_serializer.py b/src/specklepy/serialization/base_object_serializer.py index 8b9088b..fa7a2db 100644 --- a/src/specklepy/serialization/base_object_serializer.py +++ b/src/specklepy/serialization/base_object_serializer.py @@ -30,6 +30,7 @@ def safe_json_loads(obj: str, obj_id=None) -> Any: f"Failed to deserialise object (id: {obj_id}). This is likely a ujson big" f" int error - falling back to json. \nError: {err}", SpeckleWarning, + stacklevel=2, ) return json.loads(obj) @@ -140,7 +141,8 @@ class BaseObjectSerializer: object_builder[prop] = value continue - # NOTE: for dynamic props, this won't be re-serialised as an enum but as an int + # NOTE: for dynamic props, this won't be re-serialised + # as an enum but as an int if isinstance(value, Enum): object_builder[prop] = value.value continue @@ -222,7 +224,7 @@ class BaseObjectSerializer: if isinstance(obj, Enum): return obj.value - elif isinstance(obj, (list, tuple, set)): + elif isinstance(obj, list | tuple | set): if not detach: return [self.traverse_value(o) for o in obj] @@ -257,6 +259,7 @@ class BaseObjectSerializer: f"Failed to handle {type(obj)} in" " `BaseObjectSerializer.traverse_value`", SpeckleWarning, + stacklevel=2, ) return str(obj) @@ -374,6 +377,7 @@ class BaseObjectSerializer: f"Could not find the referenced child object of id `{ref_id}`" f" in the given read transport: {self.read_transport.name}", SpeckleWarning, + stacklevel=2, ) base.__setattr__(prop, self.handle_value(value)) @@ -437,6 +441,7 @@ class BaseObjectSerializer: f"Could not find the referenced child object of id `{ref_id}` in the" f" given read transport: {self.read_transport.name}", SpeckleWarning, + stacklevel=2, ) return obj diff --git a/src/specklepy/transports/memory.py b/src/specklepy/transports/memory.py index 3be9e98..eefb77e 100644 --- a/src/specklepy/transports/memory.py +++ b/src/specklepy/transports/memory.py @@ -27,8 +27,8 @@ class MemoryTransport(AbstractTransport): ) -> None: raise NotImplementedError - def get_object(self, id: str) -> str or None: - return self.objects[id] if id in self.objects else None + def get_object(self, id: str) -> str | None: + return self.objects.get(id, None) def has_objects(self, id_list: List[str]) -> Dict[str, bool]: return {id: (id in self.objects) for id in id_list} diff --git a/src/specklepy/transports/server/batch_sender.py b/src/specklepy/transports/server/batch_sender.py index bb35b95..74cf0ff 100644 --- a/src/specklepy/transports/server/batch_sender.py +++ b/src/specklepy/transports/server/batch_sender.py @@ -11,7 +11,7 @@ from specklepy.logging.exceptions import SpeckleException LOG = logging.getLogger(__name__) -class BatchSender(object): +class BatchSender: def __init__( self, server_url, @@ -123,8 +123,14 @@ class BatchSender(object): upload_data = "[" + ",".join(new_objects) + "]" upload_data_gzip = gzip.compress(upload_data.encode()) LOG.info( - "Uploading batch of %s objects (%s new): (size: %s, compressed size: %s)" - % (len(batch), len(new_objects), len(upload_data), len(upload_data_gzip)) + "Uploading batch of {batch_size} objects {new_object_count}: ", + "(size: {upload_size}, compressed size: {upload_data_size})", + { + "batch_size": len(batch), + "new_object_count": len(new_objects), + "upload_size": len(upload_data), + "upload_data_size": len(upload_data_gzip), + }, ) try: diff --git a/src/specklepy/transports/server/server.py b/src/specklepy/transports/server/server.py index 7f6e521..e4c32c5 100644 --- a/src/specklepy/transports/server/server.py +++ b/src/specklepy/transports/server/server.py @@ -74,7 +74,8 @@ class ServerTransport(AbstractTransport): SpeckleWarning( "Unauthenticated Speckle Client provided to Server Transport" f" for {url}. Receiving from private streams will fail." - ) + ), + stacklevel=2, ) else: self.account = client.account diff --git a/src/specklepy/transports/sqlite.py b/src/specklepy/transports/sqlite.py index 085bedd..ce9f47b 100644 --- a/src/specklepy/transports/sqlite.py +++ b/src/specklepy/transports/sqlite.py @@ -39,8 +39,7 @@ class SQLiteTransport(AbstractTransport): 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, - ) + ) from ex def __repr__(self) -> str: return f"SQLiteTransport(app: '{self.app_name}', scope: '{self.scope}')" @@ -105,10 +104,9 @@ class SQLiteTransport(AbstractTransport): raise SpeckleException( "Could not save the batch of objects to the local db. Inner exception:" f" {ex}", - ex, - ) + ) from ex - def get_object(self, id: str) -> str or None: + def get_object(self, id: str) -> str | None: self.__check_connection() with closing(self.__connection.cursor()) as c: row = c.execute( diff --git a/tests/integration/client/current/test_active_user_resource.py b/tests/integration/client/current/test_active_user_resource.py index 388d0ac..e70479b 100644 --- a/tests/integration/client/current/test_active_user_resource.py +++ b/tests/integration/client/current/test_active_user_resource.py @@ -44,7 +44,8 @@ class TestActiveUserResource: def test_active_user_get_projects_with_filter(self, client: SpeckleClient): # Since the client may be reused for other tests, - # this test does rely on no other test creating a project with "Search for me" in its name + # this test does rely on no other test creating a project + # with "Search for me" in its name p1 = client.project.create( ProjectCreateInput(name="Search for me!", description=None, visibility=None) ) diff --git a/tests/integration/client/deprecated/test_other_user.py b/tests/integration/client/deprecated/test_other_user.py index d388f71..b1dc5cb 100644 --- a/tests/integration/client/deprecated/test_other_user.py +++ b/tests/integration/client/deprecated/test_other_user.py @@ -32,8 +32,8 @@ class TestOtherUser: assert isinstance(fetched_user, LimitedUser) assert fetched_user.name == second_user_dict["name"] # changed in the server, now you cannot get emails of other users - # not checking this, since the first user could or could not be an admin on the server - # admins can get emails of others, regular users can't + # not checking this, since the first user could or could not be an admin + # on the server, admins can get emails of others, regular users can't # assert fetched_user.email == None second_user_dict["id"] = fetched_user.id diff --git a/tests/integration/client/deprecated/test_user.py b/tests/integration/client/deprecated/test_user.py index 77e5374..f47e6d3 100644 --- a/tests/integration/client/deprecated/test_user.py +++ b/tests/integration/client/deprecated/test_user.py @@ -35,8 +35,8 @@ class TestUser: assert isinstance(fetched_user, User) assert fetched_user.name == second_user_dict["name"] # changed in the server, now you cannot get emails of other users - # not checking this, since the first user could or could not be an admin on the server - # admins can get emails of others, regular users can't + # not checking this, since the first user could or could not be an admin + # on the server, admins can get emails of others, regular users can't # assert fetched_user.email == None second_user_dict["id"] = fetched_user.id