Compare commits

..

6 Commits

Author SHA1 Message Date
Jedd Morgan 32dca397a3 Merge branch 'v3-dev' into jrm/speckle-client-https 2025-08-20 10:41:17 +01:00
Jedd Morgan 48759746dc fixed import 2025-07-22 11:57:56 +01:00
Jedd Morgan 4d5fb64893 Merge remote-tracking branch 'origin/v3-dev' into jrm/speckle-client-https 2025-07-22 11:50:27 +01:00
Jedd Morgan 6a3247aafa format 2025-07-22 11:49:32 +01:00
Jedd Morgan ae0280a630 format 2025-07-22 11:33:44 +01:00
Jedd Morgan 698b2a79fe Use ssl on client if only if url is https 2025-07-22 11:32:51 +01:00
14 changed files with 118 additions and 179 deletions
+5 -4
View File
@@ -7,7 +7,7 @@
</h3> </h3>
<p align="center"><b>Speckle</b> is the data infrastructure for the AEC industry.</p><br/> <p align="center"><b>Speckle</b> is the data infrastructure for the AEC industry.</p><br/>
<p align="center"><a href="https://twitter.com/SpeckleSystems"><img src="https://img.shields.io/twitter/follow/SpeckleSystems?style=social" alt="Twitter Follow"></a> <a href="https://speckle.community"><img src="https://img.shields.io/discourse/users?server=https%3A%2F%2Fspeckle.community&amp;style=flat-square&amp;logo=discourse&amp;logoColor=white" alt="Community forum users"></a> <a href="https://speckle.systems"><img src="https://img.shields.io/badge/https://-speckle.systems-royalblue?style=flat-square" alt="website"></a> <a href="https://docs.speckle.systems/dev/"><img src="https://img.shields.io/badge/docs-docs.speckle.systems-orange?style=flat-square&amp;logo=read-the-docs&amp;logoColor=white" alt="docs"></a></p> <p align="center"><a href="https://twitter.com/SpeckleSystems"><img src="https://img.shields.io/twitter/follow/SpeckleSystems?style=social" alt="Twitter Follow"></a> <a href="https://speckle.community"><img src="https://img.shields.io/discourse/users?server=https%3A%2F%2Fspeckle.community&amp;style=flat-square&amp;logo=discourse&amp;logoColor=white" alt="Community forum users"></a> <a href="https://speckle.systems"><img src="https://img.shields.io/badge/https://-speckle.systems-royalblue?style=flat-square" alt="website"></a> <a href="https://speckle.guide/dev/"><img src="https://img.shields.io/badge/docs-speckle.guide-orange?style=flat-square&amp;logo=read-the-docs&amp;logoColor=white" alt="docs"></a></p>
<p align="center"><a href="https://github.com/specklesystems/speckle-blender/"><img src="https://circleci.com/gh/specklesystems/speckle-blender.svg?style=svg&amp;circle-token=76eabd350ea243575cbb258b746ed3f471f7ac29" alt="Speckle-Next"></a> </p> <p align="center"><a href="https://github.com/specklesystems/speckle-blender/"><img src="https://circleci.com/gh/specklesystems/speckle-blender.svg?style=svg&amp;circle-token=76eabd350ea243575cbb258b746ed3f471f7ac29" alt="Speckle-Next"></a> </p>
# About Speckle # About Speckle
@@ -25,19 +25,20 @@ What is Speckle? Check our ![YouTube Video Views](https://img.shields.io/youtube
- **GraphQL API:** get what you need anywhere you want it - **GraphQL API:** get what you need anywhere you want it
- **Webhooks:** the base for a automation and next-gen pipelines - **Webhooks:** the base for a automation and next-gen pipelines
- **Built for developers:** we are building Speckle with developers in mind and got tools for every stack - **Built for developers:** we are building Speckle with developers in mind and got tools for every stack
- **Built for the AEC industry:** Speckle connectors are plugins for the most common software used in the industry such as Revit, Rhino, Grasshopper, AutoCAD, Civil 3D, Blender and more! - **Built for the AEC industry:** Speckle connectors are plugins for the most common software used in the industry such as Revit, Rhino, Grasshopper, AutoCAD, Civil 3D, Excel, Unreal Engine, Unity, QGIS, Blender and more!
### Try Speckle now! ### Try Speckle now!
Give Speckle a try in no time by: Give Speckle a try in no time by:
- [![speckle XYZ](https://img.shields.io/badge/https://-app.speckle.systems-0069ff?style=flat-square&logo=hackthebox&logoColor=white)](https://app.speckle.systems) ⇒ creating an account at our public server - [![speckle XYZ](https://img.shields.io/badge/https://-speckle.xyz-0069ff?style=flat-square&logo=hackthebox&logoColor=white)](https://speckle.xyz) ⇒ creating an account at our public server
- [![create a droplet](https://img.shields.io/badge/Create%20a%20Droplet-0069ff?style=flat-square&logo=digitalocean&logoColor=white)](https://marketplace.digitalocean.com/apps/speckle-server?refcode=947a2b5d7dc1) ⇒ deploying an instance in 1 click
### Resources ### Resources
- [![Community forum users](https://img.shields.io/badge/community-forum-green?style=for-the-badge&logo=discourse&logoColor=white)](https://speckle.community) for help, feature requests or just to hang with other speckle enthusiasts, check out our community forum! - [![Community forum users](https://img.shields.io/badge/community-forum-green?style=for-the-badge&logo=discourse&logoColor=white)](https://speckle.community) for help, feature requests or just to hang with other speckle enthusiasts, check out our community forum!
- [![website](https://img.shields.io/badge/tutorials-speckle.systems-royalblue?style=for-the-badge&logo=youtube)](https://speckle.systems) our tutorials portal is full of resources to get you started using Speckle - [![website](https://img.shields.io/badge/tutorials-speckle.systems-royalblue?style=for-the-badge&logo=youtube)](https://speckle.systems) our tutorials portal is full of resources to get you started using Speckle
- [![docs](https://img.shields.io/badge/docs-docs.speckle.systems-orange?style=for-the-badge&logo=read-the-docs&logoColor=white)](https://docs.speckle.systems/connectors/blender) reference on almost any end-user and developer functionality - [![docs](https://img.shields.io/badge/docs-speckle.guide-orange?style=for-the-badge&logo=read-the-docs&logoColor=white)](https://speckle.guide/user/blender.html) reference on almost any end-user and developer functionality
# Blender Connector # Blender Connector
@@ -1,7 +1,7 @@
import bpy import bpy
from bpy.types import Context, Event, UILayout from bpy.types import Context, Event, UILayout
from specklepy.core.api.inputs import CreateModelInput from specklepy.core.api.inputs import CreateModelInput
from typing import Tuple from specklepy.core.api.models import Model
from ..utils.account_manager import _client_cache from ..utils.account_manager import _client_cache
@@ -21,12 +21,12 @@ class SPECKLE_OT_create_model(bpy.types.Operator):
return {"CANCELLED"} return {"CANCELLED"}
try: try:
model_id, model_name = create_model( model = _create_model(
wm.selected_account_id, wm.selected_project_id, self.model_name wm.selected_account_id, wm.selected_project_id, self.model_name
) )
wm.selected_model_id = model_id wm.selected_model_id = model.id
wm.selected_model_name = model_name wm.selected_model_name = model.name
self.report({"INFO"}, f"Created model: {model_name} -> ID: {model_id}") self.report({"INFO"}, f"Created model: {model.name} -> ID: {model.id}")
# Force redraw # Force redraw
context.window.screen = context.window.screen context.window.screen = context.window.screen
context.area.tag_redraw() context.area.tag_redraw()
@@ -51,19 +51,17 @@ def unregister() -> None:
bpy.utils.unregister_class(SPECKLE_OT_create_model) bpy.utils.unregister_class(SPECKLE_OT_create_model)
def create_model(account_id: str, project_id: str, model_name: str) -> Tuple[str, str]: def _create_model(account_id: str, project_id: str, model_name: str) -> Model:
try: try:
# Get cached client # Get cached client
client = _client_cache.get_client(account_id) client = _client_cache.get_client(account_id)
if not client:
raise ValueError(f"Could not get client for account: {account_id}")
model = client.model.create( model = client.model.create(
input=CreateModelInput( input=CreateModelInput(
name=model_name, description="", project_id=project_id name=model_name, description="", project_id=project_id
) )
) )
return (model.id, model.name) return model
except Exception as e: except Exception as e:
# Clear cache on error to prevent stale clients # Clear cache on error to prevent stale clients
_client_cache.clear() _client_cache.clear()
@@ -1,10 +1,11 @@
from typing import Optional
import bpy import bpy
from bpy.types import Context, Event, UILayout from bpy.types import Context, Event, UILayout
from specklepy.core.api.enums import ProjectVisibility
from specklepy.core.api.inputs import ProjectCreateInput from specklepy.core.api.inputs import ProjectCreateInput
from specklepy.core.api.inputs.project_inputs import WorkspaceProjectCreateInput from specklepy.core.api.inputs.project_inputs import WorkspaceProjectCreateInput
from specklepy.core.api.enums import ProjectVisibility from specklepy.core.api.models import Project
from typing import Tuple, Optional
from ..utils.account_manager import _client_cache from ..utils.account_manager import _client_cache
@@ -22,16 +23,16 @@ class SPECKLE_OT_create_project(bpy.types.Operator):
def execute(self, context: Context) -> set[str]: def execute(self, context: Context) -> set[str]:
wm = context.window_manager wm = context.window_manager
project_id, project_name = create_project( project = _create_project(
wm.selected_account_id, wm.selected_account_id,
self.project_name, self.project_name,
None None
if wm.selected_workspace.id == "personal" if wm.selected_workspace.id == "personal"
else wm.selected_workspace.id, else wm.selected_workspace.id,
) )
wm.selected_project_id = project_id wm.selected_project_id = project.id
wm.selected_project_name = project_name wm.selected_project_name = project.name
self.report({"INFO"}, f"Created project: {project_name} -> ID: {project_id}") self.report({"INFO"}, f"Created project: {project.name} -> ID: {project.id}")
# Force redraw # Force redraw
context.window.screen = context.window.screen context.window.screen = context.window.screen
context.area.tag_redraw() context.area.tag_redraw()
@@ -53,20 +54,19 @@ def unregister() -> None:
bpy.utils.unregister_class(SPECKLE_OT_create_project) bpy.utils.unregister_class(SPECKLE_OT_create_project)
def create_project( def _create_project(
account_id: str, project_name: str, workspace_id: Optional[str] account_id: str, project_name: str, workspace_id: Optional[str]
) -> Tuple[str, str]: ) -> Project:
try: try:
# Get cached client # Get cached client
client = _client_cache.get_client(account_id) client = _client_cache.get_client(account_id)
if not client:
raise Exception(f"Could not get client for account: {account_id}")
if workspace_id: if workspace_id:
project = client.project.create_in_workspace( project = client.project.create_in_workspace(
input=WorkspaceProjectCreateInput( input=WorkspaceProjectCreateInput(
name=project_name, name=project_name,
description="", description="",
visibility=ProjectVisibility("PUBLIC"), visibility=ProjectVisibility.PUBLIC,
workspaceId=workspace_id, workspaceId=workspace_id,
) )
) )
@@ -75,11 +75,11 @@ def create_project(
input=ProjectCreateInput( input=ProjectCreateInput(
name=project_name, name=project_name,
description="", description="",
visibility=ProjectVisibility("PUBLIC"), visibility=ProjectVisibility.PUBLIC,
) )
) )
return (project.id, project.name) return project
except Exception as e: except Exception as e:
print(f"Failed to create project: {str(e)}") print(f"Failed to create project: {str(e)}")
# Clear cache on error to prevent stale clients # Clear cache on error to prevent stale clients
@@ -1,25 +1,25 @@
from typing import Dict, Union
import bpy import bpy
from bpy.types import Context from bpy.types import Context
from specklepy.transports.server import ServerTransport from specklepy.core.api import host_applications, operations
from specklepy.core.api import operations from specklepy.logging import metrics
from specklepy.objects.models.collections.collection import Collection as SCollection
from specklepy.objects.graph_traversal.default_traversal import ( from specklepy.objects.graph_traversal.default_traversal import (
create_default_traversal_function, create_default_traversal_function,
) )
from specklepy.core.api import host_applications from specklepy.objects.models.collections.collection import Collection as SCollection
from specklepy.transports.server import ServerTransport
from ..utils.get_ascendants import get_ascendants from ... import bl_info
from ..utils.account_manager import _client_cache
from ...converter.utils import find_object_by_id, get_project_workspace_id
from ...converter.to_native import ( from ...converter.to_native import (
convert_to_native, convert_to_native,
render_material_proxy_to_native,
instance_definition_proxy_to_native,
find_instance_definitions, find_instance_definitions,
instance_definition_proxy_to_native,
render_material_proxy_to_native,
) )
from specklepy.logging import metrics from ...converter.utils import find_object_by_id
from ... import bl_info from ..utils.account_manager import _client_cache
from typing import Dict, Union from ..utils.get_ascendants import get_ascendants
def load_operation( def load_operation(
@@ -33,9 +33,6 @@ def load_operation(
# get cached client # get cached client
client = _client_cache.get_client(context.window_manager.selected_account_id) client = _client_cache.get_client(context.window_manager.selected_account_id)
if not client:
print("No Speckle client found")
return {}
print(f"Using client for account: {context.window_manager.selected_account_id}") print(f"Using client for account: {context.window_manager.selected_account_id}")
@@ -48,36 +45,21 @@ def load_operation(
metrics.set_host_app("blender") metrics.set_host_app("blender")
# Get account for metrics tracking metrics.track(
from specklepy.core.api.credentials import get_local_accounts metrics.RECEIVE,
client.account,
account = next( {
( "ui": "dui3",
acc "hostAppVersion": ".".join(map(str, bl_info["blender"])),
for acc in get_local_accounts() "core_version": ".".join(map(str, bl_info["version"])),
if acc.id == context.window_manager.selected_account_id "sourceHostApp": host_applications.get_host_app_from_string(
), version.source_application
None, ).slug,
"isMultiplayer": version.author_user.id != client.account.userInfo.id,
"workspace_id": client.project.get(wm.selected_project_id).workspace_id,
},
) )
if account:
metrics.track(
metrics.RECEIVE,
account,
{
"ui": "dui3",
"hostAppVersion": ".".join(map(str, bl_info["blender"])),
"core_version": ".".join(map(str, bl_info["version"])),
"sourceHostApp": host_applications.get_host_app_from_string(
version.source_application
).slug,
"isMultiplayer": version.author_user.id != account.userInfo.id,
"workspace_id": get_project_workspace_id(
client, wm.selected_project_id
),
},
)
# Create material mapping first # Create material mapping first
material_mapping = render_material_proxy_to_native(version_data) material_mapping = render_material_proxy_to_native(version_data)
@@ -1,22 +1,22 @@
import bpy from typing import Dict, List, Optional, Tuple
from bpy.types import Context, Collection as BlenderCollection
from typing import List, Optional, Dict, Tuple
import bpy
from bpy.types import Collection as BlenderCollection
from bpy.types import Context
from specklepy.core.api import operations
from specklepy.core.api.inputs.version_inputs import CreateVersionInput
from specklepy.logging import metrics
from specklepy.objects import Base from specklepy.objects import Base
from specklepy.objects.models.collections.collection import Collection from specklepy.objects.models.collections.collection import Collection
from specklepy.core.api import operations
from specklepy.transports.server import ServerTransport
from specklepy.core.api.inputs.version_inputs import CreateVersionInput
from specklepy.objects.models.units import Units from specklepy.objects.models.units import Units
from specklepy.transports.server import ServerTransport
from ... import bl_info
from ...converter.to_speckle import convert_to_speckle from ...converter.to_speckle import convert_to_speckle
from ...converter.to_speckle.material_to_speckle import ( from ...converter.to_speckle.material_to_speckle import (
add_render_material_proxies_to_base, add_render_material_proxies_to_base,
) )
from ...converter.utils import get_project_workspace_id
from ..utils.account_manager import _client_cache from ..utils.account_manager import _client_cache
from specklepy.logging import metrics
from ... import bl_info
def publish_operation( def publish_operation(
@@ -33,8 +33,6 @@ def publish_operation(
try: try:
# get cached client # get cached client
client = _client_cache.get_client(wm.selected_account_id) client = _client_cache.get_client(wm.selected_account_id)
if not client:
return False, "No Speckle client found", None
transport = ServerTransport(stream_id=wm.selected_project_id, client=client) transport = ServerTransport(stream_id=wm.selected_project_id, client=client)
@@ -52,40 +50,29 @@ def publish_operation(
obj_id = operations.send(root_collection, [transport]) obj_id = operations.send(root_collection, [transport])
version_input = CreateVersionInput( version_input = CreateVersionInput(
objectId=obj_id, object_id=obj_id,
modelId=wm.selected_model_id, model_id=wm.selected_model_id,
projectId=wm.selected_project_id, project_id=wm.selected_project_id,
message=version_message, message=version_message,
sourceApplication="blender", source_application="blender",
) )
version = client.version.create(version_input) version = client.version.create(version_input)
version_id = version.id version_id = version.id
# Get account for metrics tracking # track metrics
from specklepy.core.api.credentials import get_local_accounts metrics.set_host_app("blender")
metrics.track(
account = next( metrics.SEND,
(acc for acc in get_local_accounts() if acc.id == wm.selected_account_id), client.account,
None, {
"ui": "dui3",
"hostAppVersion": ".".join(map(str, bl_info["blender"])),
"core_version": ".".join(map(str, bl_info["version"])),
"workspace_id": client.project.get(wm.selected_project_id).workspace_id,
},
) )
if account:
# track metrics
metrics.set_host_app("blender")
metrics.track(
metrics.SEND,
account,
{
"ui": "dui3",
"hostAppVersion": ".".join(map(str, bl_info["blender"])),
"core_version": ".".join(map(str, bl_info["version"])),
"workspace_id": get_project_workspace_id(
client, wm.selected_project_id
),
},
)
# count total objects for success message # count total objects for success message
total_objects = count_objects_in_collection(root_collection) total_objects = count_objects_in_collection(root_collection)
@@ -123,11 +123,7 @@ def update_workspaces_list(context: Context) -> None:
workspace: speckle_workspace = wm.speckle_workspaces.add() workspace: speckle_workspace = wm.speckle_workspaces.add()
workspace.id = id workspace.id = id
workspace.name = name workspace.name = name
active_workspace = get_active_workspace(wm.selected_account_id) wm.selected_workspace.id = get_active_workspace(wm.selected_account_id)["id"]
if active_workspace:
wm.selected_workspace.id = active_workspace["id"]
else:
wm.selected_workspace.id = "personal"
print("Updated Workspaces List!") print("Updated Workspaces List!")
@@ -1,5 +1,6 @@
import bpy import bpy
from bpy.types import UILayout, Context, PropertyGroup, Event from bpy.types import Context, Event, PropertyGroup, UILayout
from ..utils.model_manager import get_models_for_project from ..utils.model_manager import get_models_for_project
from ..utils.version_manager import get_latest_version from ..utils.version_manager import get_latest_version
@@ -120,13 +120,10 @@ class SPECKLE_OT_project_selection_dialog(bpy.types.Operator):
if wm.selected_account_id == "": if wm.selected_account_id == "":
wm.selected_account_id = get_default_account_id() wm.selected_account_id = get_default_account_id()
active_workspace = get_active_workspace(wm.selected_account_id) wm.selected_workspace.id = get_active_workspace(wm.selected_account_id)["id"]
if active_workspace: wm.selected_workspace.name = get_active_workspace(wm.selected_account_id)[
wm.selected_workspace.id = active_workspace["id"] "name"
wm.selected_workspace.name = active_workspace["name"] ]
else:
wm.selected_workspace.id = "personal"
wm.selected_workspace.name = "Personal Projects"
# Fetch projects from server # Fetch projects from server
projects: List[Tuple[str, str, str, str, bool]] = get_projects_for_account( projects: List[Tuple[str, str, str, str, bool]] = get_projects_for_account(
+10 -4
View File
@@ -1,9 +1,10 @@
from typing import Dict, List, Optional, Tuple
import bpy import bpy
from specklepy.core.api.credentials import get_local_accounts
from typing import List, Tuple, Optional, Dict
from specklepy.core.api.credentials import Account
from specklepy.core.api.client import SpeckleClient from specklepy.core.api.client import SpeckleClient
from specklepy.core.api.credentials import Account, get_local_accounts
from specklepy.core.api.wrapper import StreamWrapper from specklepy.core.api.wrapper import StreamWrapper
from .misc import strip_non_ascii from .misc import strip_non_ascii
@@ -23,7 +24,11 @@ class SpeckleClientCache:
if not account: if not account:
raise ValueError(f"No account found for ID: {account_id}") raise ValueError(f"No account found for ID: {account_id}")
client = SpeckleClient(host=account.serverInfo.url) assert account.serverInfo.url
client = SpeckleClient(
host=account.serverInfo.url,
use_ssl=account.serverInfo.url.startswith("https"),
)
client.authenticate_with_account(account) client.authenticate_with_account(account)
self._clients[account_id] = client self._clients[account_id] = client
return client return client
@@ -179,6 +184,7 @@ def get_project_from_url(
try: try:
wrapper = StreamWrapper(url) wrapper = StreamWrapper(url)
account = wrapper.get_account() account = wrapper.get_account()
assert account.id
client = _client_cache.get_client(account.id) client = _client_cache.get_client(account.id)
# get the stream_id (project_id) from the wrapper # get the stream_id (project_id) from the wrapper
+5 -11
View File
@@ -1,8 +1,10 @@
from typing import List, Optional, Tuple
from specklepy.core.api.inputs.project_inputs import ProjectModelsFilter from specklepy.core.api.inputs.project_inputs import ProjectModelsFilter
from specklepy.core.api.models.current import Model from specklepy.core.api.models.current import Model
from typing import List, Tuple, Optional
from .misc import format_relative_time, strip_non_ascii
from .account_manager import _client_cache from .account_manager import _client_cache
from .misc import format_relative_time, strip_non_ascii
def get_models_for_project( def get_models_for_project(
@@ -18,17 +20,9 @@ def get_models_for_project(
) )
return [] return []
# Get cached client
client = _client_cache.get_client(account_id) client = _client_cache.get_client(account_id)
if not client:
print(f"Error: Could not get client for account: {account_id}")
return []
try: client.project.get(project_id)
client.project.get(project_id)
except Exception as e:
print(f"Error: Project with ID {project_id} not found: {str(e)}")
return []
filter = ProjectModelsFilter(search=search) if search else None filter = ProjectModelsFilter(search=search) if search else None
+13 -9
View File
@@ -1,14 +1,16 @@
from typing import List, Optional, Tuple
from specklepy.core.api.client import SpeckleClient from specklepy.core.api.client import SpeckleClient
from specklepy.core.api.resources.current.workspace_resource import WorkspaceResource
from specklepy.core.api.inputs.project_inputs import WorksaceProjectsFilter
from typing import List, Tuple, Optional
from specklepy.core.api.credentials import Account from specklepy.core.api.credentials import Account
from .misc import format_relative_time, format_role, strip_non_ascii from specklepy.core.api.inputs.project_inputs import WorksaceProjectsFilter
from specklepy.core.api.resources.current.workspace_resource import WorkspaceResource
from .account_manager import _client_cache from .account_manager import _client_cache
from .misc import format_relative_time, format_role, strip_non_ascii
def get_projects_for_account( def get_projects_for_account(
account_id: str, workspace_id: str = None, search: Optional[str] = None account_id: str, workspace_id: str, search: Optional[str] = None
) -> List[Tuple[str, str, str, str, bool]]: ) -> List[Tuple[str, str, str, str, bool]]:
""" """
fetches projects for a given account from the Speckle server fetches projects for a given account from the Speckle server
@@ -102,12 +104,13 @@ def _get_personal_projects_with_permissions(
helper function to get personal projects with permissions using the old method helper function to get personal projects with permissions using the old method
""" """
from specklepy.core.api.inputs.user_inputs import UserProjectsFilter from specklepy.core.api.inputs.user_inputs import UserProjectsFilter
from .account_manager import can_load from .account_manager import can_load
filter = UserProjectsFilter( filter = UserProjectsFilter(
search=search, search=search,
workspaceId=None, workspace_id=None,
personalOnly=True, personal_only=True,
include_implicit_access=True, include_implicit_access=True,
) )
@@ -141,12 +144,13 @@ def _get_projects_with_individual_permissions(
Fallback helper function to get projects with permissions using individual API calls Fallback helper function to get projects with permissions using individual API calls
""" """
from specklepy.core.api.inputs.user_inputs import UserProjectsFilter from specklepy.core.api.inputs.user_inputs import UserProjectsFilter
from .account_manager import can_load from .account_manager import can_load
filter = UserProjectsFilter( filter = UserProjectsFilter(
search=search, search=search,
workspaceId=workspace_id, workspace_id=workspace_id,
personalOnly=False, personal_only=False,
include_implicit_access=True, include_implicit_access=True,
) )
+7 -15
View File
@@ -1,10 +1,11 @@
from specklepy.core.api.client import SpeckleClient
from .account_manager import _client_cache
from typing import List, Tuple from typing import List, Tuple
from .misc import format_relative_time
from specklepy.core.api.inputs.model_inputs import ModelVersionsFilter from specklepy.core.api.client import SpeckleClient
from specklepy.core.api.models.current import Version from specklepy.core.api.models.current import Version
from .account_manager import _client_cache
from .misc import format_relative_time
def get_versions_for_model( def get_versions_for_model(
account_id: str, project_id: str, model_id: str account_id: str, project_id: str, model_id: str
@@ -20,17 +21,11 @@ def get_versions_for_model(
) )
return [] return []
# Get cached client
client: SpeckleClient = _client_cache.get_client(account_id) client: SpeckleClient = _client_cache.get_client(account_id)
if not client:
print(f"Error: Could not get client for account: {account_id}")
return []
filter: ModelVersionsFilter = ModelVersionsFilter(priorityIds=[])
# Get versions # Get versions
versions: List[Version] = client.version.get_versions( versions = client.version.get_versions(
project_id=project_id, model_id=model_id, limit=10, filter=filter project_id=project_id, model_id=model_id, limit=10
) )
versions_list: List[Tuple[str, str, str]] = [] versions_list: List[Tuple[str, str, str]] = []
for version in versions.items: for version in versions.items:
@@ -66,9 +61,6 @@ def get_latest_version(
# Get cached client # Get cached client
client: SpeckleClient = _client_cache.get_client(account_id) client: SpeckleClient = _client_cache.get_client(account_id)
if not client:
print(f"Error: Could not get client for account: {account_id}")
return ("", "", "")
# Get versions (limit to 1 since we only need the latest) # Get versions (limit to 1 since we only need the latest)
versions: List[Version] = client.version.get_versions( versions: List[Version] = client.version.get_versions(
-19
View File
@@ -5,7 +5,6 @@ from specklepy.objects import Base
from specklepy.objects.graph_traversal.default_traversal import ( from specklepy.objects.graph_traversal.default_traversal import (
create_default_traversal_function, create_default_traversal_function,
) )
from specklepy.core.api.client import SpeckleClient
def to_rgba(argb_int: int) -> Tuple[float, float, float, float]: def to_rgba(argb_int: int) -> Tuple[float, float, float, float]:
@@ -187,21 +186,3 @@ def find_object_by_id(root_object: Base, target_id: str) -> Optional[Base]:
return None return None
return deep_search(root_object) return deep_search(root_object)
def get_project_workspace_id(client: SpeckleClient, project_id: str) -> Optional[str]:
workspace_id = None
server_version = client.project.server_version or client.server.version()
# Local yarn builds of server will report a server version if "dev"
# We'll assume that local builds are up-to-date with the latest features
if server_version[0] == "dev":
maj = 999
min = 999
else:
maj = server_version[0]
min = server_version[1]
if maj > 2 or (maj == 2 and min > 20):
workspace_id = client.project.get(project_id).workspace_id
return workspace_id
+1 -1
View File
@@ -5,7 +5,7 @@ description = "Next-Gen Speckle connector for Blender!"
requires-python = ">=3.11.9, <4.0.0" requires-python = ">=3.11.9, <4.0.0"
license = "Apache-2.0" license = "Apache-2.0"
dependencies = [ dependencies = [
"specklepy>=3.0.4", "specklepy>=3.0.3",
] ]
[dependency-groups] [dependency-groups]