Compare commits

..

6 Commits

Author SHA1 Message Date
Dogukan Karatas c04a97780c update from main 2025-11-11 08:56:16 +01:00
Dogukan Karatas c5cd69569e docs poc 2025-03-05 12:50:44 +01:00
Jedd Morgan e38249bc38 Moved docs one layer higher 2025-02-28 16:37:54 +00:00
Jedd Morgan 08fbf59c8a experiments 2025-02-28 16:21:43 +00:00
Jedd Morgan e9cdd3e900 round2 2025-02-28 15:34:59 +00:00
Jedd Morgan 20bb0449e8 first pass 2025-02-28 15:10:44 +00:00
135 changed files with 1586 additions and 4311 deletions
-6
View File
@@ -13,14 +13,12 @@ jobs:
name: Test (internal)
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version:
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"
steps:
- uses: actions/checkout@v4
@@ -61,17 +59,13 @@ jobs:
test-public: # Run integration tests against the public server image
name: Test (public)
runs-on: ubuntu-latest
env:
IS_PUBLIC: "true"
strategy:
fail-fast: false
matrix:
python-version:
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"
steps:
- uses: actions/checkout@v4
-1
View File
@@ -1 +0,0 @@
words = ["specklepy"]
+4 -1
View File
@@ -97,7 +97,10 @@ services:
STRATEGY_LOCAL: "true"
POSTGRES_URL: 'postgres://speckle:speckle@postgres:5432/speckle'
POSTGRES_URL: "postgres"
POSTGRES_USER: "speckle"
POSTGRES_PASSWORD: "speckle"
POSTGRES_DB: "speckle"
ENABLE_MP: "false"
LOG_PRETTY: "true"
-50
View File
@@ -1,50 +0,0 @@
# specklepy API Reference
> The Python SDK for Speckle - Build powerful AEC data workflows
**specklepy** is the Python SDK for Speckle, enabling you to interact with Speckle Server, send and receive geometry, and build custom integrations for the AEC industry.
## What is specklepy?
specklepy is a comprehensive Python library that provides:
* **Object-based data exchange** - Send and receive geometry and BIM data without files
* **GraphQL API client** - Full access to Speckle Server's API
* **Extensible object model** - Create custom objects that inherit from `Base`
* **Multiple transport options** - Store data locally (SQLite), in-memory, or on Speckle Server
* **Geometry support** - Rich geometric primitives (Point, Line, Mesh, etc.)
## Speckle Automate
Speckle Automate is a fully fledged CI/CD platform designed to run custom code on Speckle models whenever a new version is available.
As a software developer, you can develop Functions that others in your team consume in Automations. From creating reports to running code compliance checks to wind simulations, there is no limit to what you can do with Automate.
## Installation
Install specklepy using pip:
```bash
pip install specklepy
```
## Quick Example
```python
from specklepy.api.client import SpeckleClient
from specklepy.api.credentials import get_default_account
from specklepy.objects.geometry import Point
# Authenticate
client = SpeckleClient(host="https://app.speckle.systems")
account = get_default_account()
client.authenticate_with_account(account)
# Create geometry
point = Point(x=10, y=20, z=5)
```
## Getting Help
- **Community Forum**: [speckle.community](https://speckle.community/c/help/developers)
- **GitHub Issues**: [github.com/specklesystems/specklepy](https://github.com/specklesystems/specklepy/issues)
@@ -1 +0,0 @@
::: speckle_automate.AutomationContext
-3
View File
@@ -1,3 +0,0 @@
::: speckle_automate.runner.execute_automate_function
::: speckle_automate.runner.run_function
-11
View File
@@ -1,11 +0,0 @@
::: speckle_automate.AutomateBase
::: speckle_automate.AutomationRunData
::: speckle_automate.AutomationResult
::: speckle_automate.ResultCase
::: speckle_automate.AutomationStatus
::: speckle_automate.ObjectResultLevel
-5
View File
@@ -1,5 +0,0 @@
::: specklepy.api.credentials.Account
::: specklepy.api.credentials.UserInfo
::: specklepy.api.credentials.StreamWrapper
-7
View File
@@ -1,7 +0,0 @@
::: specklepy.api.operations.send
::: specklepy.api.operations.receive
::: specklepy.api.operations.serialize
::: specklepy.api.operations.deserialize
@@ -1 +0,0 @@
::: specklepy.api.resources.ActiveUserResource
@@ -1 +0,0 @@
::: specklepy.api.resources.FileImportResource
@@ -1 +0,0 @@
::: specklepy.api.resources.ModelResource
@@ -1 +0,0 @@
::: specklepy.api.resources.OtherUserResource
@@ -1 +0,0 @@
::: specklepy.api.resources.ProjectInviteResource
@@ -1 +0,0 @@
::: specklepy.api.resources.ProjectResource
@@ -1 +0,0 @@
::: specklepy.api.resources.ServerResource
@@ -1 +0,0 @@
::: specklepy.api.resources.SubscriptionResource
@@ -1 +0,0 @@
::: specklepy.api.resources.VersionResource
@@ -1 +0,0 @@
::: specklepy.api.resources.WorkspaceResource
-1
View File
@@ -1 +0,0 @@
::: specklepy.core.api.enums.ProjectVisibility
-11
View File
@@ -1,11 +0,0 @@
::: specklepy.core.api.inputs.ProjectCreateInput
::: specklepy.core.api.inputs.ProjectUpdateInput
::: specklepy.core.api.inputs.CreateModelInput
::: specklepy.core.api.inputs.UpdateModelInput
::: specklepy.core.api.inputs.CreateVersionInput
::: specklepy.core.api.inputs.UpdateVersionInput
-13
View File
@@ -1,13 +0,0 @@
::: specklepy.core.api.models.User
::: specklepy.core.api.models.LimitedUser
::: specklepy.core.api.models.ServerInfo
::: specklepy.core.api.models.Project
::: specklepy.core.api.models.Model
::: specklepy.core.api.models.Version
::: specklepy.core.api.models.current.Workspace
-7
View File
@@ -1,7 +0,0 @@
::: specklepy.logging.exceptions.SpeckleException
::: specklepy.logging.exceptions.GraphQLException
::: specklepy.logging.exceptions.SerializationException
::: specklepy.logging.exceptions.SpeckleWarning
-3
View File
@@ -1,3 +0,0 @@
::: specklepy.objects.Base
::: specklepy.objects.base.DataChunk
-5
View File
@@ -1,5 +0,0 @@
::: specklepy.objects.DataObject
::: specklepy.objects.QgisObject
::: specklepy.objects.BlenderObject
-1
View File
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Arc
-1
View File
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Box
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Circle
@@ -1 +0,0 @@
::: specklepy.objects.geometry.ControlPoint
-1
View File
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Curve
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Ellipse
-1
View File
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Line
-1
View File
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Mesh
-1
View File
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Plane
-1
View File
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Point
@@ -1 +0,0 @@
::: specklepy.objects.geometry.PointCloud
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Polycurve
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Polyline
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Spiral
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Surface
@@ -1 +0,0 @@
::: specklepy.objects.geometry.Vector
@@ -1,7 +0,0 @@
::: specklepy.objects.graph_traversal.GraphTraversal
::: specklepy.objects.graph_traversal.TraversalContext
::: specklepy.objects.graph_traversal.TraversalRule
::: specklepy.objects.graph_traversal.DefaultRule
@@ -1 +0,0 @@
::: specklepy.objects.models.collections.collection.Collection
@@ -1 +0,0 @@
::: specklepy.objects.proxies.LevelProxy
@@ -1 +0,0 @@
::: specklepy.serialization.base_object_serializer.BaseObjectSerializer
-7
View File
@@ -1,7 +0,0 @@
::: specklepy.transports.abstract_transport.AbstractTransport
::: specklepy.transports.memory.MemoryTransport
::: specklepy.transports.sqlite.SQLiteTransport
::: specklepy.transports.server.ServerTransport
-304
View File
@@ -1,304 +0,0 @@
.md-content h1 {
font-size: 1.125rem;
font-weight: 700;
color: #111827;
letter-spacing: -0.025em;
line-height: 1.2;
}
@media (min-width: 640px) {
.md-content h1 {
font-size: 1.25rem;
}
}
[data-md-color-scheme="slate"] .md-content h1 {
color: #e5e7eb;
}
.md-content h2 {
font-size: 1rem;
font-weight: 700;
color: #111827;
letter-spacing: -0.025em;
margin-top: 2rem;
}
@media (min-width: 640px) {
.md-content h2 {
font-size: 1.125rem;
}
}
[data-md-color-scheme="slate"] .md-content h2 {
color: #e5e7eb;
}
.md-content h3 {
font-size: 0.9375rem;
font-weight: 600;
color: #1f2937;
margin-top: 1.5rem;
}
@media (min-width: 640px) {
.md-content h3 {
font-size: 1rem;
}
}
[data-md-color-scheme="slate"] .md-content h3 {
color: #d1d5db;
}
.md-content p,
.md-content li {
font-size: 0.875rem;
line-height: 1.6;
color: #374151;
margin-top: 0.5rem;
}
[data-md-color-scheme="slate"] .md-content p,
[data-md-color-scheme="slate"] .md-content li {
color: #d1d5db;
}
.doc.doc-object-name {
font-size: 1.125rem;
font-weight: 700;
color: #111827;
}
[data-md-color-scheme="slate"] .doc.doc-object-name {
color: #e5e7eb;
}
.doc.doc-heading {
font-size: 0.9375rem;
font-weight: 600;
color: #1f2937;
}
[data-md-color-scheme="slate"] .doc.doc-heading {
color: #d1d5db;
}
.md-content code {
font-size: 0.75rem;
color: #dc2626;
background-color: #f3f4f6;
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
}
[data-md-color-scheme="slate"] .md-content code {
color: #fca5a5;
background-color: #1f2937;
}
.md-content pre code {
font-size: 0.75rem;
color: inherit;
background-color: transparent;
padding: 0;
}
.md-content a {
color: #2563eb;
text-decoration: none;
}
.md-content a:hover {
color: #1d4ed8;
text-decoration: underline;
}
[data-md-color-scheme="slate"] .md-content a {
color: #60a5fa;
}
[data-md-color-scheme="slate"] .md-content a:hover {
color: #93c5fd;
}
[data-md-color-scheme="slate"] {
--md-default-bg-color: #000000;
--md-default-fg-color: #ffffff;
--md-code-bg-color: #0a0a0a;
--md-code-fg-color: #ffffff;
}
[data-md-color-scheme="slate"] .md-header {
background-color: #000000;
}
[data-md-color-scheme="slate"] .md-tabs {
background-color: #000000;
}
[data-md-color-scheme="slate"] .md-footer {
background-color: #000000;
}
[data-md-color-scheme="slate"] .md-sidebar {
background-color: #000000;
}
[data-md-color-scheme="slate"] .md-nav {
background-color: #000000;
}
.highlight pre,
.highlight code {
background-color: #f6f8fa !important;
color: #24292e !important;
}
.highlight .k,
.highlight .kc,
.highlight .kd,
.highlight .kn,
.highlight .kp,
.highlight .kr,
.highlight .kt {
color: #d73a49 !important;
}
.highlight .s,
.highlight .s1,
.highlight .s2,
.highlight .sb,
.highlight .sc,
.highlight .sd,
.highlight .se,
.highlight .sh,
.highlight .si,
.highlight .sx,
.highlight .sr,
.highlight .ss {
color: #032f62 !important;
}
.highlight .nf,
.highlight .fm,
.highlight .nc {
color: #6f42c1 !important;
}
.highlight .m,
.highlight .mf,
.highlight .mh,
.highlight .mi,
.highlight .mo {
color: #005cc5 !important;
}
.highlight .c,
.highlight .c1,
.highlight .cm,
.highlight .cp,
.highlight .cs {
color: #6a737d !important;
font-style: italic;
}
.highlight .o,
.highlight .ow {
color: #d73a49 !important;
}
.highlight .n,
.highlight .na,
.highlight .nb,
.highlight .nd,
.highlight .ni,
.highlight .nl,
.highlight .nn,
.highlight .nx,
.highlight .py,
.highlight .nt,
.highlight .nv,
.highlight .bp,
.highlight .vc,
.highlight .vg,
.highlight .vi {
color: #e36209 !important;
}
[data-md-color-scheme="slate"] .highlight pre,
[data-md-color-scheme="slate"] .highlight code {
background-color: #0d1117 !important;
color: #e6edf3 !important;
}
[data-md-color-scheme="slate"] .highlight .k,
[data-md-color-scheme="slate"] .highlight .kc,
[data-md-color-scheme="slate"] .highlight .kd,
[data-md-color-scheme="slate"] .highlight .kn,
[data-md-color-scheme="slate"] .highlight .kp,
[data-md-color-scheme="slate"] .highlight .kr,
[data-md-color-scheme="slate"] .highlight .kt {
color: #ff7b72 !important;
}
[data-md-color-scheme="slate"] .highlight .s,
[data-md-color-scheme="slate"] .highlight .s1,
[data-md-color-scheme="slate"] .highlight .s2,
[data-md-color-scheme="slate"] .highlight .sb,
[data-md-color-scheme="slate"] .highlight .sc,
[data-md-color-scheme="slate"] .highlight .sd,
[data-md-color-scheme="slate"] .highlight .se,
[data-md-color-scheme="slate"] .highlight .sh,
[data-md-color-scheme="slate"] .highlight .si,
[data-md-color-scheme="slate"] .highlight .sx,
[data-md-color-scheme="slate"] .highlight .sr,
[data-md-color-scheme="slate"] .highlight .ss {
color: #a5d6ff !important;
}
[data-md-color-scheme="slate"] .highlight .nf,
[data-md-color-scheme="slate"] .highlight .fm,
[data-md-color-scheme="slate"] .highlight .nc {
color: #d2a8ff !important;
}
[data-md-color-scheme="slate"] .highlight .m,
[data-md-color-scheme="slate"] .highlight .mf,
[data-md-color-scheme="slate"] .highlight .mh,
[data-md-color-scheme="slate"] .highlight .mi,
[data-md-color-scheme="slate"] .highlight .mo {
color: #79c0ff !important;
}
[data-md-color-scheme="slate"] .highlight .c,
[data-md-color-scheme="slate"] .highlight .c1,
[data-md-color-scheme="slate"] .highlight .cm,
[data-md-color-scheme="slate"] .highlight .cp,
[data-md-color-scheme="slate"] .highlight .cs {
color: #8b949e !important;
font-style: italic;
}
[data-md-color-scheme="slate"] .highlight .o,
[data-md-color-scheme="slate"] .highlight .ow {
color: #ff7b72 !important;
}
[data-md-color-scheme="slate"] .highlight .n,
[data-md-color-scheme="slate"] .highlight .na,
[data-md-color-scheme="slate"] .highlight .nb,
[data-md-color-scheme="slate"] .highlight .nd,
[data-md-color-scheme="slate"] .highlight .ni,
[data-md-color-scheme="slate"] .highlight .nl,
[data-md-color-scheme="slate"] .highlight .nn,
[data-md-color-scheme="slate"] .highlight .nx,
[data-md-color-scheme="slate"] .highlight .py,
[data-md-color-scheme="slate"] .highlight .nt,
[data-md-color-scheme="slate"] .highlight .nv,
[data-md-color-scheme="slate"] .highlight .bp,
[data-md-color-scheme="slate"] .highlight .vc,
[data-md-color-scheme="slate"] .highlight .vg,
[data-md-color-scheme="slate"] .highlight .vi {
color: #ffa657 !important;
}
-21
View File
@@ -1,27 +1,6 @@
[tools]
python = "3.13.7"
uv = "0.9.11"
[settings]
experimental = true
python.uv_venv_auto = true
[tasks.install]
run= "uv sync --all-extras --all-groups"
[tasks.install_docs]
run= "uv sync --group docs"
[tasks.build_docs]
description = "Build static docs "
run = "uv run mkdocs build"
depends = ['install_docs']
[tasks.test]
run = "uv run pytest"
[env]
IS_PUBLIC = "false"
-130
View File
@@ -1,130 +0,0 @@
site_name: specklepy Docs
theme:
name: material
font:
text: Inter
favicon: assets/speckle_logo.png
logo: assets/speckle_logo.png
features:
- navigation.tabs
palette:
# Palette toggle for light mode
- scheme: default
primary: white
toggle:
icon: material/weather-night
name: Switch to dark mode
# Palette toggle for dark mode
- scheme: slate
primary: black
logo: assets/logo_white.png
toggle:
icon: material/weather-sunny
name: Switch to light mode
markdown_extensions:
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.snippets
- pymdownx.superfences
extra_css:
- stylesheets/extra.css
plugins:
- search
- mkdocstrings:
handlers:
python:
paths: [src]
options:
parameter_headings: false
members_order: source
separate_signature: true
filters: ["!^_"] #Ignore _ prefixed properties
docstring_options:
ignore_init_summary: true
merge_init_into_class: true
show_signature_annotations: true
signature_crossrefs: true
show_if_no_docstring: true
show_labels: true
show_source: true
show_symbol_type_heading: true
show_symbol_type_toc: true
show_bases: false
heading_level: 3
inventories:
- url: https://docs.python.org/3/objects.inv
domains: [py, std]
nav:
- Home: index.md
- specklepy SDK:
- API:
- Client: specklepy/api/client.md
- Credentials: specklepy/api/credentials.md
- Operations: specklepy/api/operations.md
- Resources:
- ActiveUserResource: specklepy/api/resources/ActiveUserResource.md
- FileImportResource: specklepy/api/resources/FileImportResource.md
- ModelResource: specklepy/api/resources/ModelResource.md
- OtherUserResource: specklepy/api/resources/OtherUserResource.md
- ProjectInviteResource: specklepy/api/resources/ProjectInviteResource.md
- ProjectResource: specklepy/api/resources/ProjectResource.md
- ServerResource: specklepy/api/resources/ServerResource.md
- SubscriptionResource: specklepy/api/resources/SubscriptionResource.md
- VersionResource: specklepy/api/resources/VersionResource.md
- WorkspaceResource: specklepy/api/resources/WorkspaceResource.md
- Objects:
- Base: specklepy/objects/base.md
- Data Objects: specklepy/objects/data_objects.md
- Geometry:
- Arc: specklepy/objects/geometry/Arc.md
- Box: specklepy/objects/geometry/Box.md
- Circle: specklepy/objects/geometry/Circle.md
- ControlPoint: specklepy/objects/geometry/ControlPoint.md
- Curve: specklepy/objects/geometry/Curve.md
- Ellipse: specklepy/objects/geometry/Ellipse.md
- Line: specklepy/objects/geometry/Line.md
- Mesh: specklepy/objects/geometry/Mesh.md
- Plane: specklepy/objects/geometry/Plane.md
- Point: specklepy/objects/geometry/Point.md
- PointCloud: specklepy/objects/geometry/PointCloud.md
- Polycurve: specklepy/objects/geometry/Polycurve.md
- Polyline: specklepy/objects/geometry/Polyline.md
- Spiral: specklepy/objects/geometry/Spiral.md
- Surface: specklepy/objects/geometry/Surface.md
- Vector: specklepy/objects/geometry/Vector.md
- Primitives:
- Interval: specklepy/objects/primitives/interval.md
- Other:
- RenderMaterial: specklepy/objects/other/render_material.md
- Collection: specklepy/objects/other/collection.md
- Proxies:
- ColorProxy: specklepy/objects/proxies/ColorProxy.md
- GroupProxy: specklepy/objects/proxies/GroupProxy.md
- InstanceProxy: specklepy/objects/proxies/InstanceProxy.md
- InstanceDefinitionProxy: specklepy/objects/proxies/InstanceDefinitionProxy.md
- LevelProxy: specklepy/objects/proxies/LevelProxy.md
- RenderMaterialProxy: specklepy/objects/proxies/RenderMaterialProxy.md
- Graph Traversal: specklepy/objects/graph_traversal/traversal.md
- Transports: specklepy/transports/transports.md
- Serialization: specklepy/serialization/serializer.md
- Core API:
- Models: specklepy/core/api/models/models.md
- Inputs: specklepy/core/api/inputs/inputs.md
- Enums: specklepy/core/api/enums.md
- Logging:
- Exceptions: specklepy/logging/exceptions.md
- Speckle Automate:
- AutomationContext: speckle_automate/automation_context.md
- Runner: speckle_automate/runner.md
- Schema: speckle_automate/schema.md
-3
View File
@@ -1,3 +0,0 @@
[build]
command = "mise run build_docs"
publish = "site"
+5 -9
View File
@@ -13,6 +13,10 @@ dependencies = [
"deprecated>=1.2.15",
"gql[requests,websockets]>=3.5.0,<4.0.0",
"httpx>=0.28.1",
"mkdocs>=1.6.1",
"mkdocs-material>=9.6.5",
"mkdocstrings>=0.28.1",
"mkdocstrings-python>=1.15.0",
"pydantic>=2.10.5",
"pydantic-settings>=2.7.1",
"ujson>=5.10.0",
@@ -22,7 +26,6 @@ dependencies = [
speckleifc = ["ifcopenshell>=0.8.3.post2"]
[dependency-groups]
dev = [
"commitizen>=4.1.0",
"devtools>=0.12.2",
@@ -33,18 +36,11 @@ dev = [
"pytest-asyncio>=0.25.2",
"pytest-cov>=6.0.0",
"pytest-ordering>=0.6",
"pytest_httpserver >=1.1.3",
"ruff==0.9.2",
"ruff>=0.9.2",
"types-deprecated>=1.2.15.20241117",
"types-requests>=2.32.0.20241016",
"types-ujson>=5.10.0.20240515",
]
docs = [
"mkdocs>=1.6.1",
"mkdocs-material>=9.6.5",
"mkdocstrings>=0.28.1",
"mkdocstrings-python>=1.15.0",
]
[project.urls]
repository = "https://github.com/specklesystems/specklepy"
@@ -0,0 +1 @@
::: specklepy.objects.data_objects.DataObject
@@ -0,0 +1 @@
::: specklepy.objects.data_objects.QgisObject
@@ -0,0 +1 @@
::: specklepy.objects.interfaces.IBlenderObject
@@ -0,0 +1 @@
::: specklepy.objects.interfaces.ICurve
@@ -0,0 +1 @@
::: specklepy.objects.interfaces.IDataObject
@@ -0,0 +1 @@
::: specklepy.objects.interfaces.IDisplayValue
@@ -0,0 +1 @@
::: specklepy.objects.interfaces.IBlenderObject
@@ -0,0 +1 @@
::: specklepy.objects.interfaces.IHasArea
@@ -0,0 +1 @@
::: specklepy.objects.interfaces.IHasUnits
@@ -0,0 +1 @@
::: specklepy.objects.interfaces.IHasVolume
@@ -0,0 +1 @@
::: specklepy.objects.interfaces.IProperties
+1
View File
@@ -0,0 +1 @@
::: specklepy.objects.base.Base
@@ -0,0 +1 @@
::: specklepy.objects.geometry.arc.Arc
@@ -0,0 +1 @@
::: specklepy.objects.geometry.box.Box
@@ -0,0 +1 @@
::: specklepy.objects.geometry.circle.Circle
@@ -0,0 +1 @@
::: specklepy.objects.geometry.control_point.ControlPoint
@@ -0,0 +1 @@
::: specklepy.objects.geometry.ellipse.Ellipse
@@ -0,0 +1 @@
::: specklepy.objects.geometry.line.Line
@@ -0,0 +1 @@
::: specklepy.objects.geometry.mesh.Mesh
@@ -0,0 +1 @@
::: specklepy.objects.geometry.plane.Plane
@@ -0,0 +1 @@
::: specklepy.objects.geometry.point.Point
@@ -0,0 +1 @@
::: specklepy.objects.geometry.point_cloud.PointCloud
@@ -0,0 +1 @@
::: specklepy.objects.geometry.polycurve.Polycurve
@@ -0,0 +1 @@
::: specklepy.objects.geometry.polyline.Polyline
@@ -0,0 +1 @@
::: specklepy.objects.geometry.spiral.Spiral
@@ -0,0 +1 @@
::: specklepy.objects.geometry.surface.Surface
@@ -0,0 +1 @@
::: specklepy.objects.geometry.vector.Vector

Before

Width:  |  Height:  |  Size: 386 B

After

Width:  |  Height:  |  Size: 386 B

+29
View File
@@ -0,0 +1,29 @@
# Introduction
Welcome to the Specklepy Developer Docs - a single source of documentation on everything Specklepy! If you're looking for info on how to use Speckle, check our [user guide](https://speckle.guide/).
### Code Repository
The Python SDK can be found in our [repository](//github.com/specklesystems/specklepy), its readme contains instructions on how to build it.
### Installation
You can install it using pip
```
pip install specklepy
```
### Key Components
SpecklePy has three main parts:
1. a `SpeckleClient` which allows you to interact with the server API
2. `operations` and `transports` for sending and receiving large objects
3. a `Base` object and accompaniying serializer for creating and customizing your own Speckle objects
### Local Data Paths
It may be helpful to know where the local accounts and object cache dbs are stored. Depending on on your OS, you can find the dbs at:
- Windows: `APPDATA` or `<USER>\AppData\Roaming\Speckle`
- Linux: `$XDG_DATA_HOME` or by default `~/.local/share/Speckle`
- Mac: `~/.config/Speckle`
@@ -0,0 +1 @@
::: speckle_automate.automation_context.AutomationContext
+64
View File
@@ -0,0 +1,64 @@
site_name: Specklepy Docs
theme:
name: material
favicon: assets/speckle_logo.png
logo: assets/speckle_logo.png
features:
- navigation.tabs
palette:
# Palette toggle for light mode
- scheme: default
primary: white
toggle:
icon: material/weather-night
name: Switch to dark mode
# Palette toggle for dark mode
- scheme: slate
primary: black
logo: assets/logo_white.png
toggle:
icon: material/weather-sunny
name: Switch to light mode
markdown_extensions:
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.snippets
- pymdownx.superfences
extra_css:
- css/mkdocstrings.css
plugins:
- search
- mkdocstrings:
handlers:
python:
paths: [.]
options:
parameter_headings: false
members_order: source
separate_signature: true
filters: ["!^_"] #Ignore _ prefixed properties
docstring_options:
ignore_init_summary: true
merge_init_into_class: true
show_signature_annotations: true
signature_crossrefs: true
show_if_no_docstring: true
show_labels: true
show_source: true
show_symbol_type_heading: true
show_symbol_type_toc: true
show_bases: false
heading_level: 3
inventories:
- url: https://docs.python.org/3/objects.inv
domains: [py, std]
+11 -24
View File
@@ -19,12 +19,8 @@ from speckle_automate.schema import (
from specklepy.api import operations
from specklepy.api.client import SpeckleClient
from specklepy.core.api.inputs.model_inputs import CreateModelInput
from specklepy.core.api.inputs.version_inputs import (
CreateVersionInput,
MarkReceivedVersionInput,
)
from specklepy.core.api.inputs.version_inputs import CreateVersionInput
from specklepy.core.api.models.current import Model, Version
from specklepy.logging import metrics
from specklepy.logging.exceptions import SpeckleException
from specklepy.objects.base import Base
from specklepy.transports.memory import MemoryTransport
@@ -70,7 +66,6 @@ class AutomationContext:
if isinstance(automation_run_data, AutomationRunData)
else AutomationRunData.model_validate_json(automation_run_data)
)
metrics.set_host_app("automate")
speckle_client = SpeckleClient(
automation_run_data.speckle_server_url,
automation_run_data.speckle_server_url.startswith("https"),
@@ -105,7 +100,6 @@ class AutomationContext:
"""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
project_id = self.automation_run_data.project_id
version_id = self.automation_run_data.triggers[0].payload.version_id
try:
version = self.speckle_client.version.get(
@@ -115,7 +109,7 @@ class AutomationContext:
raise ValueError(
f"""Could not receive specified version.
Is your environment configured correctly?
project_id: {project_id}
project_id: {self.automation_run_data.project_id}
model_id: {self.automation_run_data.triggers[0].payload.model_id}
version_id: {self.automation_run_data.triggers[0].payload.version_id}
"""
@@ -130,13 +124,6 @@ class AutomationContext:
base = operations.receive(
version.referenced_object, self._server_transport, self._memory_transport
)
self.speckle_client.version.received(
MarkReceivedVersionInput(
version_id=version_id,
project_id=project_id,
source_application="automate_function",
)
)
# self._closure_tree = base["__closure"]
print(
f"It took {self.elapsed():.2f} seconds to receive",
@@ -493,29 +480,29 @@ class AutomationContext:
Args:
level: Result level.
category (str): A short tag for the event type.
affected_objects (Union[Base, List[Base]]): A single object, a list of
objects, or an empty list. When empty, a result case is still
appended with no object IDs (e.g. for skipped rules or version-level
messages).
affected_objects (Union[Base, List[Base]]): A single object or a list of
objects that are causing the info case.
message (Optional[str]): Optional message.
metadata: User provided metadata key value pairs
visual_overrides: Case specific 3D visual overrides.
"""
if isinstance(affected_objects, list):
if len(affected_objects) < 1:
raise ValueError(
f"Need atleast one object to report a(n) {level.value.upper()}"
)
object_list = affected_objects
else:
object_list = [affected_objects]
ids: Dict[str, Optional[str]] = {}
# When objects are provided, each must have an id (empty list allowed for
# version-level/skipped results).
for o in object_list:
if not getattr(o, "id", None):
# validate that the Base.id is not None. If its a None, throw an Exception
if not o.id:
raise Exception(
f"You can only attach {level} results to objects with an id."
)
ids[o.id] = getattr(o, "applicationId", None)
ids[o.id] = o.applicationId
print(
f"Created new {level.value.upper()}"
f" category: {category} caused by: {message}"
+3 -6
View File
@@ -18,7 +18,7 @@ def cmd_line_import() -> None:
parser.add_argument("output_path")
parser.add_argument("project_id")
parser.add_argument("version_message")
parser.add_argument("model_ingestion_id")
parser.add_argument("model_id")
# parser.add_argument("model_name")
# parser.add_argument("region_name")
@@ -32,8 +32,6 @@ def cmd_line_import() -> None:
"ifc",
)
client: SpeckleClient | None = None
try:
client = SpeckleClient(SERVER_URL, use_ssl=not SERVER_URL.startswith("http://"))
client.authenticate_with_token(TOKEN)
@@ -43,14 +41,13 @@ def cmd_line_import() -> None:
args.file_path,
project,
args.version_message,
args.model_ingestion_id,
args.model_id,
client,
)
with open(args.output_path, "w") as f:
json.dump({"success": True, "commitId": version.id}, f)
except Exception as e:
stack_trace = traceback.format_exc()
error_msg = f"IFC Importer failed with exception:\n{stack_trace}"
error_msg = f"IFC Importer failed with exception:\n{traceback.format_exc()}"
print(error_msg)
# Write error result
@@ -12,23 +12,12 @@ def data_object_to_speckle(
step_element: entity_instance,
children: list[Base],
current_storey: str | None = None,
parent_element: entity_instance | None = None,
) -> DataObject:
guid = cast(str, step_element.GlobalId)
name = cast(str, step_element.Name or guid)
properties = extract_properties(step_element)
# Add parent ID only if element's parent is also a DataObject (not a Collection)
# Collections are: IfcProject and IfcSpatialStructureElement types
if (
parent_element
and hasattr(parent_element, "GlobalId")
and not parent_element.is_a("IfcProject")
and not parent_element.is_a("IfcSpatialStructureElement")
):
properties["parentApplicationId"] = parent_element.GlobalId
# Add building storey information if available and not a building storey itself
if current_storey and not step_element.is_a("IfcBuildingStorey"):
properties["Building Storey"] = current_storey
+1 -7
View File
@@ -51,10 +51,4 @@ def open_ifc(file_path: str) -> file:
def create_geometry_iterator(ifc_file: file | sqlite) -> iterator:
GEOMETRY_LIBRARY = "hybrid-opencascade-cgal" # First OCC then fallback to CGAL
return iterator(
_create_iterator_settings(),
ifc_file,
multiprocessing.cpu_count(),
geometry_library=GEOMETRY_LIBRARY, # type: ignore
)
return iterator(_create_iterator_settings(), ifc_file, multiprocessing.cpu_count())
+6 -18
View File
@@ -44,13 +44,9 @@ class ImportJob:
_display_value_cache: dict[int, list[Base]] = field(default_factory=dict)
"""Maps an instance step ID to a list of instances"""
def convert_element(
self,
step_element: entity_instance,
parent_element: entity_instance | None = None,
) -> Base:
def convert_element(self, step_element: entity_instance) -> Base:
try:
return self._convert_element(step_element, parent_element)
return self._convert_element(step_element)
except SpeckleException:
raise
except Exception as ex:
@@ -58,18 +54,14 @@ class ImportJob:
f"Failed to convert {step_element.is_a()} #{step_element.id()}"
) from ex
def _convert_element(
self,
step_element: entity_instance,
parent_element: entity_instance | None = None,
) -> Base:
def _convert_element(self, step_element: entity_instance) -> Base:
# Track current storey context and store for level proxies
previous_storey_data_object = self._current_storey_data_object
if step_element.is_a("IfcBuildingStorey"):
# Convert the building storey to a DataObject for the level proxy
storey_display_value = self._display_value_cache.get(step_element.id(), [])
self._current_storey_data_object = data_object_to_speckle(
storey_display_value, step_element, [], parent_element=None
storey_display_value, step_element, []
)
children = self._convert_children(step_element)
@@ -94,11 +86,7 @@ class ImportJob:
)
else:
result = data_object_to_speckle(
display_value,
step_element,
children,
current_storey_name,
parent_element,
display_value, step_element, children, current_storey_name
)
# Associate non-spatial elements with current storey for level proxies
if self._current_storey_data_object is not None and result.applicationId:
@@ -112,7 +100,7 @@ class ImportJob:
def _convert_children(self, step_element: entity_instance) -> list[Base]:
return [
self.convert_element(i, parent_element=step_element)
self.convert_element(i)
for i in get_children(step_element)
if self._should_convert(i)
]
+34 -101
View File
@@ -1,19 +1,9 @@
import contextlib
import importlib.metadata
import time
import traceback
from pathlib import Path
from speckleifc.ifc_geometry_processing import open_ifc
from speckleifc.importer import ImportJob
from specklepy.core.api.client import SpeckleClient
from specklepy.core.api.inputs.model_ingestion_inputs import (
ModelIngestionFailedInput,
ModelIngestionStartProcessingInput,
ModelIngestionSuccessInput,
ModelIngestionUpdateInput,
SourceDataInput,
)
from specklepy.core.api.inputs.version_inputs import CreateVersionInput
from specklepy.core.api.models.current import Project, Version
from specklepy.core.api.operations import send
from specklepy.logging import metrics
@@ -23,106 +13,49 @@ from specklepy.transports.server import ServerTransport
def open_and_convert_file(
file_path: str,
project: Project,
version_message: str,
model_ingestion_id: str,
version_message: str | None,
model_id: str,
client: SpeckleClient,
) -> Version:
try:
start = time.time()
very_start = start
path = Path(file_path)
start = time.time()
very_start = start
specklepy_version = importlib.metadata.version("specklepy")
client.model_ingestion.start_processing(
ModelIngestionStartProcessingInput(
project_id=project.id,
ingestion_id=model_ingestion_id,
progress_message="Importing IFC file",
source_data=SourceDataInput(
file_name=path.name,
file_size_bytes=path.stat().st_size,
source_application_slug=metrics.HOST_APP,
source_application_version=specklepy_version,
),
)
)
account = client.account
server_url = account.serverInfo.url
assert server_url
remote_transport = ServerTransport(project.id, account=account)
account = client.account
server_url = account.serverInfo.url
assert server_url
remote_transport = ServerTransport(project.id, account=account)
ifc_file = open_ifc(file_path) # pyright: ignore[reportUnknownVariableType]
ifc_file = open_ifc(file_path) # pyright: ignore[reportUnknownVariableType]
import_job = ImportJob(ifc_file) # pyright: ignore[reportUnknownArgumentType]
data = import_job.convert()
client.model_ingestion.update_progress(
ModelIngestionUpdateInput(
project_id=project.id,
ingestion_id=model_ingestion_id,
progress_message="Converting file",
progress=None,
)
)
import_job = ImportJob(ifc_file) # pyright: ignore[reportUnknownArgumentType]
data = import_job.convert()
print(f"File conversion complete after {(time.time() - start) * 1000}ms")
print(f"File conversion complete after {(time.time() - start) * 1000}ms")
start = time.time()
start = time.time()
root_id = send(data, transports=[remote_transport], use_default_cache=False)
print(f"Sending to speckle complete after: {(time.time() - start) * 1000}ms")
client.model_ingestion.update_progress(
ModelIngestionUpdateInput(
project_id=project.id,
ingestion_id=model_ingestion_id,
progress_message="Uploading objects",
progress=None,
)
)
root_id = send(data, transports=[remote_transport], use_default_cache=False)
print(f"Sending to speckle complete after: {(time.time() - start) * 1000}ms")
start = time.time()
start = time.time()
create_version = CreateVersionInput(
object_id=root_id,
model_id=model_id,
project_id=project.id,
message=version_message,
source_application="ifc",
)
version = client.version.create(create_version)
end = time.time()
print(f"Version committed after: {(end - start) * 1000}ms")
version_id = client.model_ingestion.complete(
ModelIngestionSuccessInput(
project_id=project.id,
ingestion_id=model_ingestion_id,
root_object_id=root_id,
version_message=version_message,
)
)
print(f"Total time (to commit): {(end - very_start) * 1000}ms")
del ifc_file
# needed to query version until ingestion api expands to serve it
version = client.version.get(version_id, project.id)
custom_properties = {"ui": "dui3", "actionSource": "import"}
if project.workspace_id:
custom_properties["workspace_id"] = project.workspace_id
metrics.track(metrics.SEND, account, custom_properties, send_sync=True)
end = time.time()
print(f"Version committed after: {(end - start) * 1000}ms")
print(f"Total time (to commit): {(end - very_start) * 1000}ms")
del ifc_file
custom_properties = {"ui": "dui3", "actionSource": "import"}
if project.workspace_id:
custom_properties["workspace_id"] = project.workspace_id
metrics.track(
metrics.SEND,
account,
custom_properties,
send_sync=True,
track_email=True,
)
return version
except Exception as e:
stack_trace = traceback.format_exc()
with contextlib.suppress(Exception):
# make sure to not report process kills when we're cancelling
client.model_ingestion.fail_with_error(
ModelIngestionFailedInput(
project_id=project.id,
ingestion_id=model_ingestion_id,
error_reason=str(e),
error_stacktrace=stack_trace,
)
)
raise e
return version
-7
View File
@@ -4,7 +4,6 @@ from specklepy.api.credentials import Account
from specklepy.api.resources import (
ActiveUserResource,
FileImportResource,
ModelIngestionResource,
ModelResource,
OtherUserResource,
ProjectInviteResource,
@@ -120,12 +119,6 @@ class SpeckleClient(CoreSpeckleClient):
client=self.httpclient,
server_version=server_version,
)
self.model_ingestion = ModelIngestionResource(
account=self.account,
basepath=self.url,
client=self.httpclient,
server_version=server_version,
)
self.file_import = FileImportResource(
account=self.account,
basepath=self.url,
-5
View File
@@ -1,8 +1,5 @@
from specklepy.api.resources.current.active_user_resource import ActiveUserResource
from specklepy.api.resources.current.file_import_resource import FileImportResource
from specklepy.api.resources.current.model_ingestion_resource import (
ModelIngestionResource,
)
from specklepy.api.resources.current.model_resource import ModelResource
from specklepy.api.resources.current.other_user_resource import OtherUserResource
from specklepy.api.resources.current.project_invite_resource import (
@@ -25,6 +22,4 @@ __all__ = [
"SubscriptionResource",
"VersionResource",
"WorkspaceResource",
"FileImportResource",
"ModelIngestionResource",
]
@@ -15,7 +15,7 @@ from specklepy.logging import metrics
class FileImportResource(CoreResource):
"""API Access class for file imports"""
"""API Access class for projects"""
def __init__(self, account, basepath, client, server_version) -> None:
super().__init__(

Some files were not shown because too many files have changed in this diff Show More