Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c04a97780c | |||
| c5cd69569e | |||
| e38249bc38 | |||
| 08fbf59c8a | |||
| e9cdd3e900 | |||
| 20bb0449e8 |
@@ -59,8 +59,6 @@ jobs:
|
||||
test-public: # Run integration tests against the public server image
|
||||
name: Test (public)
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
IS_PUBLIC: "true"
|
||||
strategy:
|
||||
matrix:
|
||||
python-version:
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
words = ["specklepy"]
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -1,3 +0,0 @@
|
||||
::: speckle_automate.runner.execute_automate_function
|
||||
|
||||
::: speckle_automate.runner.run_function
|
||||
@@ -1,11 +0,0 @@
|
||||
::: speckle_automate.AutomateBase
|
||||
|
||||
::: speckle_automate.AutomationRunData
|
||||
|
||||
::: speckle_automate.AutomationResult
|
||||
|
||||
::: speckle_automate.ResultCase
|
||||
|
||||
::: speckle_automate.AutomationStatus
|
||||
|
||||
::: speckle_automate.ObjectResultLevel
|
||||
@@ -1,5 +0,0 @@
|
||||
::: specklepy.api.credentials.Account
|
||||
|
||||
::: specklepy.api.credentials.UserInfo
|
||||
|
||||
::: specklepy.api.credentials.StreamWrapper
|
||||
@@ -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 +0,0 @@
|
||||
::: specklepy.core.api.enums.ProjectVisibility
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1,7 +0,0 @@
|
||||
::: specklepy.logging.exceptions.SpeckleException
|
||||
|
||||
::: specklepy.logging.exceptions.GraphQLException
|
||||
|
||||
::: specklepy.logging.exceptions.SerializationException
|
||||
|
||||
::: specklepy.logging.exceptions.SpeckleWarning
|
||||
@@ -1,3 +0,0 @@
|
||||
::: specklepy.objects.Base
|
||||
|
||||
::: specklepy.objects.base.DataChunk
|
||||
@@ -1,5 +0,0 @@
|
||||
::: specklepy.objects.DataObject
|
||||
|
||||
::: specklepy.objects.QgisObject
|
||||
|
||||
::: specklepy.objects.BlenderObject
|
||||
@@ -1 +0,0 @@
|
||||
::: specklepy.objects.geometry.Arc
|
||||
@@ -1 +0,0 @@
|
||||
::: specklepy.objects.geometry.Box
|
||||
@@ -1 +0,0 @@
|
||||
::: specklepy.objects.geometry.Circle
|
||||
@@ -1 +0,0 @@
|
||||
::: specklepy.objects.geometry.ControlPoint
|
||||
@@ -1 +0,0 @@
|
||||
::: specklepy.objects.geometry.Curve
|
||||
@@ -1 +0,0 @@
|
||||
::: specklepy.objects.geometry.Ellipse
|
||||
@@ -1 +0,0 @@
|
||||
::: specklepy.objects.geometry.Line
|
||||
@@ -1 +0,0 @@
|
||||
::: specklepy.objects.geometry.Mesh
|
||||
@@ -1 +0,0 @@
|
||||
::: specklepy.objects.geometry.Plane
|
||||
@@ -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
|
||||
@@ -1,7 +0,0 @@
|
||||
::: specklepy.transports.abstract_transport.AbstractTransport
|
||||
|
||||
::: specklepy.transports.memory.MemoryTransport
|
||||
|
||||
::: specklepy.transports.sqlite.SQLiteTransport
|
||||
|
||||
::: specklepy.transports.server.ServerTransport
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -1,3 +0,0 @@
|
||||
[build]
|
||||
command = "mise run build_docs"
|
||||
publish = "site"
|
||||
+5
-9
@@ -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
|
||||
@@ -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 |
@@ -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
|
||||
@@ -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]
|
||||
@@ -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}"
|
||||
|
||||
@@ -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
|
||||
@@ -61,4 +58,4 @@ def cmd_line_import() -> None:
|
||||
if __name__ == "__main__":
|
||||
start = time.time()
|
||||
cmd_line_import()
|
||||
print(f"Total time (including cleanup): {(time.time() - start):.3f}s")
|
||||
print(f"Total time (including cleanup): {(time.time() - start) * 1000}ms")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -22,15 +22,12 @@ from specklepy.objects import Base
|
||||
from specklepy.objects.data_objects import DataObject
|
||||
from specklepy.objects.models.collections.collection import Collection
|
||||
from specklepy.objects.proxies import InstanceProxy
|
||||
from specklepy.progress.ingestion_progress import IngestionProgressManager
|
||||
|
||||
|
||||
@dataclass
|
||||
class ImportJob:
|
||||
ifc_file: file
|
||||
|
||||
progress: IngestionProgressManager
|
||||
|
||||
_render_material_manager: RenderMaterialProxyManager = field(
|
||||
default_factory=lambda: RenderMaterialProxyManager()
|
||||
)
|
||||
@@ -42,19 +39,14 @@ class ImportJob:
|
||||
)
|
||||
geometries_count: int = 0
|
||||
geometries_used: int = 0
|
||||
elements_converted: int = 0
|
||||
_current_storey_data_object: DataObject | None = field(default=None, init=False)
|
||||
|
||||
_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:
|
||||
@@ -62,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)
|
||||
@@ -98,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,17 +96,11 @@ class ImportJob:
|
||||
|
||||
# Restore previous storey context
|
||||
self._current_storey_data_object = previous_storey_data_object
|
||||
self.elements_converted += 1
|
||||
if self.progress.should_report_progress():
|
||||
self.progress.report(
|
||||
f"Converted {self.elements_converted:,} elements", None
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
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)
|
||||
]
|
||||
@@ -142,16 +120,12 @@ class ImportJob:
|
||||
def convert(self) -> Base:
|
||||
start = time.time()
|
||||
self.pre_process_geometry()
|
||||
print(
|
||||
f"Geometry conversion complete after {(time.time() - start):.3f}s" # noqa: E501
|
||||
)
|
||||
print(f"Geometry conversion complete after {(time.time() - start) * 1000}ms")
|
||||
print(f"Created {self.geometries_count} geometries")
|
||||
|
||||
start = time.time()
|
||||
root = self._convert_project_tree()
|
||||
print(
|
||||
f"Element tree conversion complete after {(time.time() - start):.3f}s" # noqa: E501
|
||||
)
|
||||
print(f"Object tree conversion complete after {(time.time() - start) * 1000}ms")
|
||||
print(f"Used {self.geometries_used} geometries")
|
||||
return root
|
||||
|
||||
@@ -159,10 +133,7 @@ class ImportJob:
|
||||
iterator = create_geometry_iterator(self.ifc_file)
|
||||
if not iterator.initialize():
|
||||
raise SpeckleException("Failed to find any geometry in file")
|
||||
|
||||
self.progress.report("Converting geometries", None)
|
||||
self.geometries_count = 0
|
||||
|
||||
while True:
|
||||
shape = cast(TriangulationElement, iterator.get())
|
||||
self.geometries_count += 1
|
||||
@@ -174,11 +145,6 @@ class ImportJob:
|
||||
raise SpeckleException(
|
||||
f"Failed to convert geometry with id: {id}"
|
||||
) from ex
|
||||
|
||||
if self.progress.should_report_progress():
|
||||
self.progress.report(
|
||||
f"Converted {self.geometries_count:,} geometries", None
|
||||
)
|
||||
if not iterator.next():
|
||||
break
|
||||
|
||||
@@ -219,8 +185,6 @@ class ImportJob:
|
||||
raise SpeckleException("Expected exactly one IfcProject in file")
|
||||
project = projects[0]
|
||||
|
||||
self.progress.report("Converting elements", None)
|
||||
|
||||
tree = self.convert_element(project)
|
||||
if not isinstance(tree, Collection):
|
||||
raise TypeError("Expected root object to convert to a Collection")
|
||||
|
||||
+33
-105
@@ -1,133 +1,61 @@
|
||||
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,
|
||||
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
|
||||
from specklepy.progress.ingestion_progress import IngestionProgressManager
|
||||
from specklepy.progress.progress_transport import ProgressTransport
|
||||
from specklepy.transports.server import ServerTransport
|
||||
|
||||
# Since progress messages are currently blocking (no async), we're being extra coarse
|
||||
# with progress updates to ensure we're not waisting time sending updates.
|
||||
# We could maybe go a little lower, but for now I'm not risking degrading performance
|
||||
PROGRESS_INTERVAL_SECONDS = 10
|
||||
|
||||
|
||||
def open_and_convert_file(
|
||||
file_path: str,
|
||||
project: Project,
|
||||
version_message: str | None,
|
||||
model_ingestion_id: str,
|
||||
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")
|
||||
ingestion = 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,
|
||||
),
|
||||
)
|
||||
)
|
||||
progress = IngestionProgressManager(
|
||||
client, ingestion, PROGRESS_INTERVAL_SECONDS
|
||||
)
|
||||
account = client.account
|
||||
server_url = account.serverInfo.url
|
||||
assert server_url
|
||||
remote_transport = ServerTransport(project.id, account=account)
|
||||
progress_transport = ProgressTransport(
|
||||
progress,
|
||||
)
|
||||
account = client.account
|
||||
server_url = account.serverInfo.url
|
||||
assert server_url
|
||||
remote_transport = ServerTransport(project.id, account=account)
|
||||
|
||||
progress.report("Opening file", None)
|
||||
ifc_file = open_ifc(file_path) # pyright: ignore[reportUnknownVariableType]
|
||||
ifc_file = open_ifc(file_path) # pyright: ignore[reportUnknownVariableType]
|
||||
|
||||
import_job = ImportJob(ifc_file, progress) # pyright: ignore[reportUnknownArgumentType]
|
||||
data = import_job.convert()
|
||||
import_job = ImportJob(ifc_file) # pyright: ignore[reportUnknownArgumentType]
|
||||
data = import_job.convert()
|
||||
|
||||
print(
|
||||
f"File conversion complete after {(time.time() - start):.3f}s" # noqa: E501
|
||||
)
|
||||
print(f"File conversion complete after {(time.time() - start) * 1000}ms")
|
||||
|
||||
start = time.time()
|
||||
start = time.time()
|
||||
|
||||
progress.report("Uploading objects", None)
|
||||
root_id = send(
|
||||
data,
|
||||
transports=[remote_transport, progress_transport],
|
||||
use_default_cache=False,
|
||||
)
|
||||
print(
|
||||
f"Sending to speckle complete after: {(time.time() - start):.3f}s" # noqa: E501
|
||||
)
|
||||
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()
|
||||
|
||||
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,
|
||||
)
|
||||
)
|
||||
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")
|
||||
|
||||
# needed to query version until ingestion api expands to serve it
|
||||
version = client.version.get(version_id, project.id)
|
||||
print(f"Total time (to commit): {(end - very_start) * 1000}ms")
|
||||
del ifc_file
|
||||
|
||||
end = time.time()
|
||||
print(f"Version committed after: {(end - start):.3f}s")
|
||||
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)
|
||||
|
||||
print(f"Total time (to commit): {(end - very_start):.3f}s")
|
||||
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
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import time
|
||||
|
||||
from speckleifc.main import open_and_convert_file
|
||||
from specklepy.api.client import SpeckleClient
|
||||
from specklepy.core.api.credentials import get_accounts_for_server
|
||||
from specklepy.logging import metrics
|
||||
|
||||
|
||||
def _manual_import() -> None:
|
||||
from specklepy.core.api.inputs.model_ingestion_inputs import (
|
||||
ModelIngestionCreateInput,
|
||||
SourceDataInput,
|
||||
)
|
||||
|
||||
PROJECT_ID = "412a3c3927"
|
||||
MODEL_ID = "223e61212d"
|
||||
SERVER_URL = "latest.speckle.systems"
|
||||
FILE_PATH = r"C:\Test Files\ifc\AC20-FZK-Haus.ifc" # noqa: E501
|
||||
|
||||
metrics.set_host_app(
|
||||
"ifc",
|
||||
)
|
||||
|
||||
account = get_accounts_for_server(SERVER_URL)[0]
|
||||
client = SpeckleClient(SERVER_URL, use_ssl=not SERVER_URL.startswith("http://"))
|
||||
client.authenticate_with_account(account)
|
||||
|
||||
ingestion = client.model_ingestion.create(
|
||||
ModelIngestionCreateInput(
|
||||
model_id=MODEL_ID,
|
||||
project_id=PROJECT_ID,
|
||||
progress_message="",
|
||||
source_data=SourceDataInput(
|
||||
source_application_slug="speckleifc",
|
||||
source_application_version="0.0.0",
|
||||
file_name=None,
|
||||
file_size_bytes=None,
|
||||
),
|
||||
max_idle_timeout_seconds=2700, # 45mins
|
||||
)
|
||||
)
|
||||
project = client.project.get(PROJECT_ID)
|
||||
|
||||
open_and_convert_file(FILE_PATH, project, None, ingestion.id, client)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
start = time.time()
|
||||
|
||||
_manual_import()
|
||||
print(f"Total time (including cleanup): {(time.time() - start):.3f}s")
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user