Merge pull request #374 from specklesystems/gergo/uvSetup
gergo/uvSetup
This commit is contained in:
+7
-100
@@ -1,108 +1,15 @@
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
codecov: codecov/codecov@3.3.0
|
||||
|
||||
# Define the jobs we want to run for this project
|
||||
jobs:
|
||||
pre-commit:
|
||||
parameters:
|
||||
config_file:
|
||||
default: ./.pre-commit-config.yaml
|
||||
description: Optional, path to pre-commit config file.
|
||||
type: string
|
||||
cache_prefix:
|
||||
default: ''
|
||||
description: |
|
||||
Optional cache prefix to be used on CircleCI. Can be used for cache busting or to ensure multiple jobs use different caches.
|
||||
type: string
|
||||
build:
|
||||
docker:
|
||||
- image: speckle/pre-commit-runner:latest
|
||||
resource_class: medium
|
||||
- image: cimg/base:2023.03
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- cache-pre-commit-<<parameters.cache_prefix>>-{{ checksum "<<parameters.config_file>>" }}
|
||||
- run:
|
||||
name: Install pre-commit hooks
|
||||
command: pre-commit install-hooks --config <<parameters.config_file>>
|
||||
- save_cache:
|
||||
key: cache-pre-commit-<<parameters.cache_prefix>>-{{ checksum "<<parameters.config_file>>" }}
|
||||
paths:
|
||||
- ~/.cache/pre-commit
|
||||
- run:
|
||||
name: Run pre-commit
|
||||
command: pre-commit run --all-files
|
||||
- run:
|
||||
command: git --no-pager diff
|
||||
name: git diff
|
||||
when: on_fail
|
||||
|
||||
test:
|
||||
machine:
|
||||
image: ubuntu-2204:2023.02.1
|
||||
docker_layer_caching: false
|
||||
resource_class: medium
|
||||
parameters:
|
||||
tag:
|
||||
default: "3.11"
|
||||
type: string
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install python
|
||||
command: |
|
||||
pyenv install -s << parameters.tag >>
|
||||
pyenv global << parameters.tag >>
|
||||
- run:
|
||||
name: Startup the Speckle Server
|
||||
command: docker compose -f docker-compose.yml up -d
|
||||
- run:
|
||||
name: Install Poetry
|
||||
command: |
|
||||
pip install poetry
|
||||
- run:
|
||||
name: Install packages
|
||||
command: poetry install
|
||||
- run:
|
||||
name: Run tests
|
||||
command: poetry run pytest --cov --cov-report xml:reports/coverage.xml --junitxml=reports/test-results.xml
|
||||
- store_test_results:
|
||||
path: reports
|
||||
- store_artifacts:
|
||||
path: reports
|
||||
- codecov/upload
|
||||
|
||||
deploy:
|
||||
docker:
|
||||
- image: "cimg/python:3.8"
|
||||
steps:
|
||||
- checkout
|
||||
- run: python patch_version.py $CIRCLE_TAG
|
||||
- run: poetry build
|
||||
- run: poetry publish -u __token__ -p $PYPI_TOKEN
|
||||
- run: echo "so long and thanks for all the fish"
|
||||
|
||||
# Orchestrate our job run sequence
|
||||
workflows:
|
||||
main:
|
||||
build_and_test:
|
||||
jobs:
|
||||
- pre-commit:
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
- test:
|
||||
matrix:
|
||||
parameters:
|
||||
tag: ["3.11"]
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
- deploy:
|
||||
context: pypi
|
||||
requires:
|
||||
- pre-commit
|
||||
- test
|
||||
filters:
|
||||
tags:
|
||||
only: /[0-9]+(\.[0-9]+)*/
|
||||
branches:
|
||||
ignore: /.*/ # For testing only! /ci\/.*/
|
||||
- build
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
name: "Specklepy test and build"
|
||||
on:
|
||||
# pull_request:
|
||||
# branches:
|
||||
# - 'v3-dev'
|
||||
push:
|
||||
branches:
|
||||
- "gergo/uvSetup"
|
||||
jobs:
|
||||
ci:
|
||||
name: continuous-integration
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version:
|
||||
- "3.10"
|
||||
- "3.11"
|
||||
- "3.12"
|
||||
- "3.13"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install uv and set the python version
|
||||
uses: astral-sh/setup-uv@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
enable-cache: true
|
||||
cache-dependency-glob: "uv.lock"
|
||||
|
||||
- name: Install the project
|
||||
run: uv sync --all-extras --dev
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pre-commit/
|
||||
key: ${{ hashFiles('.pre-commit-config.yaml') }}
|
||||
|
||||
- name: Run pre-commit
|
||||
run: uv run pre-commit run --all-files
|
||||
|
||||
# - name: Run Speckle Server
|
||||
# run: docker compose up -d
|
||||
|
||||
# - name: Run tests
|
||||
# run: uv run pytest --cov --cov-report xml:reports/coverage.xml --junitxml=reports/test-results.xml
|
||||
|
||||
# - uses: codecov/codecov-action@v5
|
||||
# if: matrix.python-version == 3.13
|
||||
# with:
|
||||
# fail_ci_if_error: true # optional (default = false)
|
||||
# files: ./reports/test-results.xml # optional
|
||||
# token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
- name: Minimize uv cache
|
||||
run: uv cache prune --ci
|
||||
@@ -0,0 +1,36 @@
|
||||
# Publish a release to PyPI.
|
||||
# name: 'Publish to PyPI'
|
||||
|
||||
# on:
|
||||
# push:
|
||||
# branches:
|
||||
# - 'gergo/uvSetup'
|
||||
|
||||
# jobs:
|
||||
# pypi-publish:
|
||||
# name: Upload to PyPI
|
||||
# runs-on: ubuntu-latest
|
||||
# environment:
|
||||
# name: release
|
||||
# permissions:
|
||||
# # For PyPI's trusted publishing.
|
||||
# id-token: write
|
||||
# steps:
|
||||
# - name: 'Install uv'
|
||||
# uses: astral-sh/setup-uv@v5
|
||||
# - uses: actions/checkout@v4
|
||||
# with:
|
||||
# # This is necessary so that we have the tags.
|
||||
# fetch-depth: 0
|
||||
# - uses: mtkennerly/dunamai-action@v1
|
||||
# with:
|
||||
# env-var: MY_VERSION
|
||||
# args: --style semver
|
||||
# - run: echo $MY_VERSION
|
||||
# - name: 'Build artifacts'
|
||||
# run: uv build
|
||||
# - name: Publish to PyPi
|
||||
# run: uv publish --publish-url https://test.pypi.org/simple/
|
||||
|
||||
# - name: Test package install
|
||||
# run: uv run --with specklepy --no-project -- python -c "import specklepy"
|
||||
+15
-17
@@ -1,33 +1,31 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
- repo: local
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
rev: v0.8.2
|
||||
name: ruff lint
|
||||
entry: uv run ruff check --force-exclude
|
||||
language: system
|
||||
types_or: [python, pyi]
|
||||
# Run the formatter.
|
||||
- id: ruff-format
|
||||
name: ruff format
|
||||
entry: uv run ruff format --force-exclude
|
||||
language: system
|
||||
types_or: [python, pyi]
|
||||
|
||||
|
||||
- repo: https://github.com/commitizen-tools/commitizen
|
||||
hooks:
|
||||
- id: commitizen
|
||||
- id: commitizen-branch
|
||||
stages:
|
||||
- push
|
||||
- pre-push
|
||||
rev: v3.13.0
|
||||
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.13.2
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 24.10.0
|
||||
hooks:
|
||||
- id: black
|
||||
# It is recommended to specify the latest version of Python
|
||||
# supported by your project here, or alternatively use
|
||||
# pre-commit's default_language_version, see
|
||||
# https://pre-commit.com/#top_level-default_language_version
|
||||
# language_version: python3.11
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.5.0
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
|
||||
@@ -25,25 +25,25 @@ Head to the [**📚 specklepy docs**](https://speckle.guide/dev/python.html) for
|
||||
|
||||
### Installation
|
||||
|
||||
This project uses python-poetry for dependency management, make sure you follow the official [docs](https://python-poetry.org/docs/#installation) to get poetry.
|
||||
This project uses uv for dependency management, make sure you follow the official [docs](https://docs.astral.sh/uv/) to get it.
|
||||
|
||||
To bootstrap the project environment run `$ poetry install`. This will create a new virtual-env for the project and install both the package and dev dependencies.
|
||||
To create a new virtual environment with uv run `$ uv venv` and follow the instructions on the screen to activate the virtual environment.
|
||||
To bootstrap the project environment run `$ uv sync`. This will install both the package and dev dependencies.
|
||||
|
||||
If this is your first time using poetry and you're used to creating your venvs within the project directory, run `poetry config virtualenvs.in-project true` to configure poetry to do the same.
|
||||
To execute any python script run `$ uv run python my_script.py`
|
||||
|
||||
To execute any python script run `$ poetry run python my_script.py`
|
||||
|
||||
> Alternatively you may roll your own virtual-env with either venv, virtualenv, pyenv-virtualenv etc. Poetry will play along an recognize if it is invoked from inside a virtual environment.
|
||||
> Alternatively you may roll your own virtual-env with either venv, virtualenv, pyenv-virtualenv etc. Uv will play along an recognize if it is invoked from inside a virtual environment.
|
||||
|
||||
### Style guide
|
||||
|
||||
All our repo wide styling linting and other rules are checked and enforced by `pre-commit`, which is included in the dev dependencies.
|
||||
All our repo wide styling linting and other rules are checked and enforced by `pre-commit`, which is included in the dev dependencies.
|
||||
It is recommended to set up `pre-commit` after installing the dependencies by running `$ pre-commit install`.
|
||||
Commiting code that doesn't adhere to the given rules, will fail the checks in our CI system.
|
||||
|
||||
### 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`
|
||||
|
||||
+1
-7
@@ -6,7 +6,7 @@ services:
|
||||
# Speckle Server dependencies
|
||||
#######
|
||||
postgres:
|
||||
image: "postgres:14.5-alpine"
|
||||
image: "postgres:16-alpine"
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_DB: speckle
|
||||
@@ -53,12 +53,6 @@ services:
|
||||
# Speckle Server
|
||||
#######
|
||||
|
||||
speckle-frontend:
|
||||
image: speckle/speckle-frontend-2:latest
|
||||
restart: always
|
||||
ports:
|
||||
- "0.0.0.0:8080:8080"
|
||||
|
||||
speckle-server:
|
||||
image: speckle/speckle-server:latest
|
||||
restart: always
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from devtools import debug
|
||||
|
||||
from specklepy.api import operations
|
||||
from specklepy.objects.geometry import Base
|
||||
from specklepy.objects.units import Units
|
||||
from specklepy.objects_v2.geometry import Base
|
||||
from specklepy.objects_v2.units import Units
|
||||
|
||||
dct = {
|
||||
"id": "1234abcd",
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
def patch(tag):
|
||||
print(f"Patching version: {tag}")
|
||||
|
||||
with open("pyproject.toml", "r") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
if "version" not in lines[2]:
|
||||
raise Exception("Invalid pyproject.toml. Could not patch version.")
|
||||
|
||||
lines[2] = f'version = "{tag}"\n'
|
||||
with open("pyproject.toml", "w") as file:
|
||||
file.writelines(lines)
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
return
|
||||
|
||||
tag = sys.argv[1]
|
||||
if not re.match(r"[0-9]+(\.[0-9]+)*$", tag):
|
||||
raise ValueError(f"Invalid tag provided: {tag}")
|
||||
|
||||
patch(tag)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Generated
-2075
File diff suppressed because it is too large
Load Diff
+56
-61
@@ -1,75 +1,70 @@
|
||||
[tool.poetry]
|
||||
[project]
|
||||
dynamic = ["version"]
|
||||
name = "specklepy"
|
||||
version = "2.17.14"
|
||||
description = "The Python SDK for Speckle 2.0"
|
||||
readme = "README.md"
|
||||
authors = ["Speckle Systems <devops@speckle.systems>"]
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/specklesystems/speckle-py"
|
||||
documentation = "https://speckle.guide/dev/py-examples.html"
|
||||
homepage = "https://speckle.systems/"
|
||||
packages = [
|
||||
{ include = "specklepy", from = "src" },
|
||||
{ include = "speckle_automate", from = "src" },
|
||||
authors = [{ name = "Speckle Systems", email = "devops@speckle.systems" }]
|
||||
license = { text = "Apache-2.0" }
|
||||
requires-python = ">=3.10.0, <4.0"
|
||||
dependencies = [
|
||||
"appdirs>=1.4.4",
|
||||
"attrs>=24.3.0",
|
||||
"deprecated>=1.2.15",
|
||||
"gql[requests,websockets]>=3.5.0",
|
||||
"httpx>=0.28.1",
|
||||
"pydantic>=2.10.5",
|
||||
"pydantic-settings>=2.7.1",
|
||||
"stringcase>=1.2.0",
|
||||
"ujson>=5.10.0",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"commitizen>=4.1.0",
|
||||
"devtools>=0.12.2",
|
||||
"pre-commit>=4.0.1",
|
||||
"pytest>=8.3.4",
|
||||
"pytest-asyncio>=0.25.2",
|
||||
"pytest-cov>=6.0.0",
|
||||
"pytest-ordering>=0.6",
|
||||
"ruff>=0.9.2",
|
||||
"types-deprecated>=1.2.15.20241117",
|
||||
"types-requests>=2.32.0.20241016",
|
||||
"types-ujson>=5.10.0.20240515",
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.10.0, <4.0"
|
||||
pydantic = "^2.5"
|
||||
appdirs = "^1.4.4"
|
||||
gql = { extras = ["requests", "websockets"], version = "^3.3.0" }
|
||||
ujson = "^5.3.0"
|
||||
Deprecated = "^1.2.13"
|
||||
stringcase = "^1.2.0"
|
||||
attrs = "^23.1.0"
|
||||
httpx = "^0.25.0"
|
||||
pydantic-settings = "^2.6.1"
|
||||
[project.urls]
|
||||
repository = "https://github.com/specklesystems/specklepy"
|
||||
documentation = "https://speckle.guide/dev/py-examples.html"
|
||||
homepage = "https://speckle.systems/"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = "24.10.0"
|
||||
isort = "^5.13.2"
|
||||
pytest = "^7.1.3"
|
||||
pytest-asyncio = "^0.23.0"
|
||||
pytest-ordering = "^0.6"
|
||||
pytest-cov = "^3.0.0"
|
||||
devtools = "^0.8.0"
|
||||
pylint = "^3.3.2"
|
||||
pydantic-settings = "^2.3.0"
|
||||
mypy = "^0.982"
|
||||
pre-commit = "^2.20.0"
|
||||
commitizen = "^3.13.0"
|
||||
ruff = "^0.8.2"
|
||||
types-deprecated = "^1.2.9"
|
||||
types-ujson = "^5.6.0.0"
|
||||
types-requests = "^2.28.11.5"
|
||||
[build-system]
|
||||
requires = ["setuptools>=64", "setuptools-scm>=8"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.black]
|
||||
exclude = '''
|
||||
/(
|
||||
\.eggs
|
||||
| \.git
|
||||
| \.hg
|
||||
| \.mypy_cache
|
||||
| \.tox
|
||||
| \.venv
|
||||
| _build
|
||||
| buck-out
|
||||
| build
|
||||
| dist
|
||||
)/
|
||||
'''
|
||||
include = '\.pyi?$'
|
||||
line-length = 88
|
||||
target-version = ["py39", "py310", "py311", "py312", "py313"]
|
||||
[tool.setuptools_scm]
|
||||
|
||||
[tool.commitizen]
|
||||
name = "cz_conventional_commits"
|
||||
version = "2.9.2"
|
||||
tag_format = "$version"
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
[tool.ruff]
|
||||
exclude = [".venv", "**/*.yml"]
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = [
|
||||
# pycodestyle
|
||||
"E",
|
||||
# Pyflakes
|
||||
"F",
|
||||
# pyupgrade
|
||||
"UP",
|
||||
# flake8-bugbear
|
||||
"B",
|
||||
# flake8-simplify
|
||||
"SIM",
|
||||
# isort
|
||||
"I",
|
||||
]
|
||||
ignore = ["UP006", "UP007", "UP035"]
|
||||
|
||||
@@ -96,7 +96,8 @@ class AutomationContext:
|
||||
|
||||
def receive_version(self) -> Base:
|
||||
"""Receive the Speckle project version that triggered this automation run."""
|
||||
# TODO: this is a quick hack to keep implementation consistency. Move to proper receive many versions
|
||||
# TODO: this is a quick hack to keep implementation consistency.
|
||||
# Move to proper receive many versions
|
||||
version_id = self.automation_run_data.triggers[0].payload.version_id
|
||||
commit = self.speckle_client.commit.get(
|
||||
self.automation_run_data.project_id, version_id
|
||||
@@ -264,7 +265,8 @@ class AutomationContext:
|
||||
|
||||
if not path_obj.exists():
|
||||
raise ValueError("The given file path doesn't exist")
|
||||
files = {path_obj.name: open(str(path_obj), "rb")}
|
||||
|
||||
files = {path_obj.name: path_obj.open("rb")}
|
||||
|
||||
url = (
|
||||
f"{self.automation_run_data.speckle_server_url}api/stream/"
|
||||
|
||||
@@ -128,7 +128,8 @@ def execute_automate_function(
|
||||
automate_function, # type: ignore
|
||||
)
|
||||
|
||||
# if we've gotten this far, the execution should technically be completed as expected
|
||||
# if we've gotten this far,
|
||||
# the execution should technically be completed as expected
|
||||
# thus exiting with 0 is the schemantically correct thing to do
|
||||
exit_code = (
|
||||
1 if automation_context.run_status == AutomationStatus.EXCEPTION else 0
|
||||
@@ -190,4 +191,4 @@ def run_function(
|
||||
if not automation_context.context_view:
|
||||
automation_context.set_context_view()
|
||||
automation_context.report_run_status()
|
||||
return automation_context
|
||||
return automation_context
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import contextlib
|
||||
|
||||
from deprecated import deprecated
|
||||
|
||||
from specklepy.api.credentials import Account
|
||||
@@ -40,7 +42,8 @@ class SpeckleClient(CoreSpeckleClient):
|
||||
client = SpeckleClient(host="app.speckle.systems") # or whatever your host is
|
||||
# client = SpeckleClient(host="localhost:3000", use_ssl=False) or use local server
|
||||
|
||||
# authenticate the client with an account (account has been added in Speckle Manager)
|
||||
# authenticate the client with an account
|
||||
# (account has been added in Speckle Manager)
|
||||
account = get_default_account()
|
||||
client.authenticate_with_account(account)
|
||||
|
||||
@@ -74,10 +77,9 @@ class SpeckleClient(CoreSpeckleClient):
|
||||
)
|
||||
|
||||
server_version = None
|
||||
try:
|
||||
|
||||
with contextlib.suppress(Exception):
|
||||
server_version = self.server.version()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.other_user = OtherUserResource(
|
||||
account=self.account,
|
||||
|
||||
@@ -2,8 +2,11 @@ from typing import List, Optional
|
||||
|
||||
# following imports seem to be unnecessary, but they need to stay
|
||||
# to not break the scripts using these functions as non-core
|
||||
from specklepy.core.api.credentials import StreamWrapper # noqa: F401
|
||||
from specklepy.core.api.credentials import Account, UserInfo # noqa: F401
|
||||
from specklepy.core.api.credentials import ( # noqa: F401
|
||||
Account,
|
||||
StreamWrapper, # noqa: F401
|
||||
UserInfo,
|
||||
)
|
||||
from specklepy.core.api.credentials import (
|
||||
get_account_from_token as core_get_account_from_token,
|
||||
)
|
||||
|
||||
@@ -53,7 +53,9 @@ def receive(
|
||||
return _untracked_receive(obj_id, remote_transport, local_transport)
|
||||
|
||||
|
||||
def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str:
|
||||
def serialize(
|
||||
base: Base, write_transports: List[AbstractTransport] | None = None
|
||||
) -> str:
|
||||
"""
|
||||
Serialize a base object. If no write transports are provided,
|
||||
the object will be serialized
|
||||
@@ -67,6 +69,8 @@ def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str
|
||||
Returns:
|
||||
str -- the serialized object
|
||||
"""
|
||||
if not write_transports:
|
||||
write_transports = []
|
||||
metrics.track(metrics.SDK, custom_props={"name": "Serialize"})
|
||||
return core_serialize(base, write_transports)
|
||||
|
||||
|
||||
@@ -138,7 +138,8 @@ class ActiveUserResource(CoreResource):
|
||||
token (Optional[str]): The token of the invite to look for (optional).
|
||||
|
||||
Returns:
|
||||
Optional[PendingStreamCollaborator]: The invite for the given stream, or None if not found.
|
||||
Optional[PendingStreamCollaborator]: The invite for the given stream,
|
||||
or None if not found.
|
||||
"""
|
||||
metrics.track(metrics.SDK, self.account, {"name": "User Active Invite Get"})
|
||||
return super().get_pending_invite(stream_id, token)
|
||||
|
||||
@@ -20,8 +20,10 @@ from specklepy.logging.exceptions import SpeckleException
|
||||
class OtherUserResource(CoreResource):
|
||||
"""
|
||||
Provides API access to other users' profiles and activities on the platform.
|
||||
This class enables fetching limited information about users, searching for users by name or email,
|
||||
and accessing user activity logs with appropriate privacy and access control measures in place.
|
||||
This class enables fetching limited information about users,
|
||||
searching for users by name or email,
|
||||
and accessing user activity logs with appropriate privacy
|
||||
and access control measures in place.
|
||||
"""
|
||||
|
||||
def __init__(self, account, basepath, client, server_version) -> None:
|
||||
@@ -64,7 +66,8 @@ class OtherUserResource(CoreResource):
|
||||
limit (int): Maximum number of search results to return.
|
||||
|
||||
Returns:
|
||||
Union[List[LimitedUser], SpeckleException]: A list of users matching the search
|
||||
Union[List[LimitedUser], SpeckleException]:
|
||||
A list of users matching the search
|
||||
query or an exception if the query is too short.
|
||||
"""
|
||||
if len(search_query) < 3:
|
||||
@@ -86,8 +89,8 @@ class OtherUserResource(CoreResource):
|
||||
cursor: Optional[datetime] = None,
|
||||
) -> ActivityCollection:
|
||||
"""
|
||||
Retrieves a collection of activities for a specified user, with optional filters for activity type,
|
||||
time frame, and pagination.
|
||||
Retrieves a collection of activities for a specified user,
|
||||
with optional filters for activity type, time frame, and pagination.
|
||||
|
||||
Args:
|
||||
user_id (str): The ID of the user whose activities are being requested.
|
||||
@@ -98,7 +101,8 @@ class OtherUserResource(CoreResource):
|
||||
cursor (Optional[datetime]): Timestamp for pagination cursor.
|
||||
|
||||
Returns:
|
||||
ActivityCollection: A collection of user activities filtered according to specified criteria.
|
||||
ActivityCollection: A collection of user activities filtered
|
||||
according to specified criteria.
|
||||
"""
|
||||
metrics.track(metrics.SDK, self.account, {"name": "Other User Activity"})
|
||||
return super().activity(user_id, limit, action_type, before, after, cursor)
|
||||
|
||||
@@ -31,7 +31,8 @@ class ServerResource(CoreResource):
|
||||
the server version in the format (major, minor, patch, (tag, build))
|
||||
eg (2, 6, 3) for a stable build and (2, 6, 4, 'alpha', 4711) for alpha
|
||||
"""
|
||||
# not tracking as it will be called along with other mutations / queries as a check
|
||||
# not tracking as it will be called along with other
|
||||
# mutations / queries as a check
|
||||
return super().version()
|
||||
|
||||
def apps(self) -> Dict:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import contextlib
|
||||
import re
|
||||
from typing import Dict
|
||||
from warnings import warn
|
||||
@@ -49,7 +50,8 @@ class SpeckleClient:
|
||||
client = SpeckleClient(host="app.speckle.systems") # or whatever your host is
|
||||
# client = SpeckleClient(host="localhost:3000", use_ssl=False) or use local server
|
||||
|
||||
# authenticate the client with an account (account has been added in Speckle Manager)
|
||||
# authenticate the client with an account
|
||||
# (account has been added in Speckle Manager)
|
||||
account = get_default_account()
|
||||
client.authenticate_with_account(account)
|
||||
|
||||
@@ -102,7 +104,8 @@ class SpeckleClient:
|
||||
|
||||
self._init_resources()
|
||||
|
||||
# ? Check compatibility with the server - i think we can skip this at this point? save a request
|
||||
# ? Check compatibility with the server
|
||||
# - i think we can skip this at this point? save a request
|
||||
# try:
|
||||
# server_info = self.server.get()
|
||||
# if isinstance(server_info, Exception):
|
||||
@@ -187,9 +190,10 @@ class SpeckleClient:
|
||||
if ex.exception.code == 403:
|
||||
warn(
|
||||
SpeckleWarning(
|
||||
"Possibly invalid token - could not authenticate Speckle Client"
|
||||
f" for server {self.url}"
|
||||
)
|
||||
"Possibly invalid token - could not authenticate "
|
||||
f"Speckle Client for server {self.url}"
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
else:
|
||||
raise ex
|
||||
@@ -203,10 +207,8 @@ class SpeckleClient:
|
||||
)
|
||||
|
||||
server_version = None
|
||||
try:
|
||||
with contextlib.suppress(Exception):
|
||||
server_version = self.server.version()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.other_user = OtherUserResource(
|
||||
account=self.account,
|
||||
@@ -283,7 +285,7 @@ class SpeckleClient:
|
||||
return attr.Resource(
|
||||
account=self.account, basepath=self.url, client=self.httpclient
|
||||
)
|
||||
except AttributeError:
|
||||
except AttributeError as ex:
|
||||
raise SpeckleException(
|
||||
f"Method {name} is not supported by the SpeckleClient class"
|
||||
)
|
||||
) from ex
|
||||
|
||||
@@ -55,7 +55,8 @@ class ServerConfiguration(BaseModel):
|
||||
objectSizeLimitBytes: int
|
||||
|
||||
|
||||
# Keeping this one all Optionals at the minute, because its used both as a deserialization model for GQL and Account Management
|
||||
# Keeping this one all Optionals at the minute,
|
||||
# because its used both as a deserialization model for GQL and Account Management
|
||||
class ServerInfo(BaseModel):
|
||||
name: Optional[str] = None
|
||||
company: Optional[str] = None
|
||||
|
||||
@@ -4,7 +4,10 @@ from typing import List, Optional
|
||||
from deprecated import deprecated
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
FE1_DEPRECATION_REASON = "Stream/Branch/Commit API is now deprecated, Use the new Project/Model/Version API functions in Client}"
|
||||
FE1_DEPRECATION_REASON = (
|
||||
"Stream/Branch/Commit API is now deprecated, "
|
||||
"Use the new Project/Model/Version API functions in Client"
|
||||
)
|
||||
FE1_DEPRECATION_VERSION = "2.20"
|
||||
|
||||
|
||||
|
||||
@@ -70,7 +70,8 @@ def receive(
|
||||
|
||||
serializer = BaseObjectSerializer(read_transport=local_transport)
|
||||
|
||||
# try local transport first. if the parent is there, we assume all the children are there and continue with deserialization using the local transport
|
||||
# try local transport first. if the parent is there, we assume all the children
|
||||
# are there and continue with deserialization using the local transport
|
||||
obj_string = local_transport.get_object(obj_id)
|
||||
if obj_string:
|
||||
return serializer.read_json(obj_string=obj_string)
|
||||
@@ -90,7 +91,9 @@ def receive(
|
||||
return serializer.read_json(obj_string=obj_string)
|
||||
|
||||
|
||||
def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str:
|
||||
def serialize(
|
||||
base: Base, write_transports: List[AbstractTransport] | None = None
|
||||
) -> str:
|
||||
"""
|
||||
Serialize a base object. If no write transports are provided,
|
||||
the object will be serialized
|
||||
@@ -104,6 +107,8 @@ def serialize(base: Base, write_transports: List[AbstractTransport] = []) -> str
|
||||
Returns:
|
||||
str -- the serialized object
|
||||
"""
|
||||
if not write_transports:
|
||||
write_transports = []
|
||||
serializer = BaseObjectSerializer(write_transports=write_transports)
|
||||
|
||||
return serializer.write_json(base)[1]
|
||||
|
||||
@@ -18,7 +18,7 @@ from specklepy.transports.sqlite import SQLiteTransport
|
||||
T = TypeVar("T", bound=BaseModel)
|
||||
|
||||
|
||||
class ResourceBase(object):
|
||||
class ResourceBase:
|
||||
def __init__(
|
||||
self,
|
||||
account: Account,
|
||||
@@ -101,7 +101,8 @@ class ResourceBase(object):
|
||||
parse_response: bool = True,
|
||||
) -> Any:
|
||||
"""Executes the GraphQL query"""
|
||||
# This method has quite complex and ambiguous typing, and counter-intuitive error handling
|
||||
# This method has quite complex and ambiguous typing,
|
||||
# and counter-intuitive error handling
|
||||
# We are going to phase it out in favour of `make_request_and_parse_response`
|
||||
try:
|
||||
with self.__lock:
|
||||
|
||||
@@ -37,10 +37,12 @@ class ActiveUserResource(ResourceBase):
|
||||
self.schema = User
|
||||
|
||||
def get(self) -> Optional[User]:
|
||||
"""Gets the currently active user profile (as extracted from the authorization header)
|
||||
"""Gets the currently active user profile
|
||||
(as extracted from the authorization header)
|
||||
|
||||
Returns:
|
||||
User -- the requested user, or none if no authentication token is provided to the Client
|
||||
User -- the requested user, or none if no authentication token
|
||||
is provided to the Client
|
||||
"""
|
||||
QUERY = gql(
|
||||
"""
|
||||
|
||||
@@ -76,14 +76,24 @@ class ModelResource(ResourceBase):
|
||||
) -> ModelWithVersions:
|
||||
QUERY = gql(
|
||||
"""
|
||||
query ModelGetWithVersions($modelId: String!, $projectId: String!, $versionsLimit: Int!, $versionsCursor: String, $versionsFilter: ModelVersionsFilter) {
|
||||
query ModelGetWithVersions(
|
||||
$modelId: String!,
|
||||
$projectId: String!,
|
||||
$versionsLimit: Int!,
|
||||
$versionsCursor: String,
|
||||
$versionsFilter: ModelVersionsFilter
|
||||
) {
|
||||
data:project(id: $projectId) {
|
||||
data:model(id: $modelId) {
|
||||
id
|
||||
name
|
||||
previewUrl
|
||||
updatedAt
|
||||
versions(limit: $versionsLimit, cursor: $versionsCursor, filter: $versionsFilter) {
|
||||
versions(
|
||||
limit: $versionsLimit,
|
||||
cursor: $versionsCursor,
|
||||
filter: $versionsFilter
|
||||
) {
|
||||
items {
|
||||
id
|
||||
referencedObject
|
||||
@@ -148,9 +158,18 @@ class ModelResource(ResourceBase):
|
||||
) -> ResourceCollection[Model]:
|
||||
QUERY = gql(
|
||||
"""
|
||||
query ProjectGetWithModels($projectId: String!, $modelsLimit: Int!, $modelsCursor: String, $modelsFilter: ProjectModelsFilter) {
|
||||
query ProjectGetWithModels(
|
||||
$projectId: String!,
|
||||
$modelsLimit: Int!,
|
||||
$modelsCursor: String,
|
||||
$modelsFilter: ProjectModelsFilter
|
||||
) {
|
||||
data:project(id: $projectId) {
|
||||
data:models(limit: $modelsLimit, cursor: $modelsCursor, filter: $modelsFilter) {
|
||||
data:models(
|
||||
limit: $modelsLimit,
|
||||
cursor: $modelsCursor,
|
||||
filter: $modelsFilter
|
||||
) {
|
||||
items {
|
||||
id
|
||||
name
|
||||
|
||||
@@ -74,7 +74,9 @@ class OtherUserResource(ResourceBase):
|
||||
archived: bool = False,
|
||||
emailOnly: bool = False,
|
||||
) -> UserSearchResultCollection:
|
||||
"""Searches for a user on the server, by name or email. The search query must be at least
|
||||
"""
|
||||
Searches for a user on the server, by name or email.
|
||||
The search query must be at least
|
||||
3 characters long
|
||||
|
||||
Arguments:
|
||||
@@ -89,8 +91,20 @@ class OtherUserResource(ResourceBase):
|
||||
|
||||
QUERY = gql(
|
||||
"""
|
||||
query UserSearch($query: String!, $limit: Int!, $cursor: String, $archived: Boolean, $emailOnly: Boolean) {
|
||||
data:userSearch(query: $query, limit: $limit, cursor: $cursor, archived: $archived, emailOnly: $emailOnly) {
|
||||
query UserSearch(
|
||||
$query: String!,
|
||||
$limit: Int!,
|
||||
$cursor: String,
|
||||
$archived: Boolean,
|
||||
$emailOnly: Boolean
|
||||
) {
|
||||
data:userSearch(
|
||||
query: $query,
|
||||
limit: $limit,
|
||||
cursor: $cursor,
|
||||
archived: $archived,
|
||||
emailOnly: $emailOnly
|
||||
) {
|
||||
cursor
|
||||
items {
|
||||
id
|
||||
|
||||
@@ -37,7 +37,10 @@ class ProjectInviteResource(ResourceBase):
|
||||
) -> ProjectWithTeam:
|
||||
QUERY = gql(
|
||||
"""
|
||||
mutation ProjectInviteCreate($projectId: ID!, $input: ProjectInviteCreateInput!) {
|
||||
mutation ProjectInviteCreate(
|
||||
$projectId: ID!,
|
||||
$input: ProjectInviteCreateInput!
|
||||
) {
|
||||
data:projectMutations {
|
||||
data:invites {
|
||||
data:create(projectId: $projectId, input: $input) {
|
||||
|
||||
@@ -65,7 +65,12 @@ class ProjectResource(ResourceBase):
|
||||
) -> ProjectWithModels:
|
||||
QUERY = gql(
|
||||
"""
|
||||
query ProjectGetWithModels($projectId: String!, $modelsLimit: Int!, $modelsCursor: String, $modelsFilter: ProjectModelsFilter) {
|
||||
query ProjectGetWithModels(
|
||||
$projectId: String!,
|
||||
$modelsLimit: Int!,
|
||||
$modelsCursor: String,
|
||||
$modelsFilter: ProjectModelsFilter
|
||||
) {
|
||||
data:project(id: $projectId) {
|
||||
id
|
||||
name
|
||||
@@ -77,7 +82,11 @@ class ProjectResource(ResourceBase):
|
||||
updatedAt
|
||||
sourceApps
|
||||
workspaceId
|
||||
models(limit: $modelsLimit, cursor: $modelsCursor, filter: $modelsFilter) {
|
||||
models(
|
||||
limit: $modelsLimit,
|
||||
cursor: $modelsCursor,
|
||||
filter: $modelsFilter
|
||||
) {
|
||||
items {
|
||||
id
|
||||
name
|
||||
|
||||
@@ -80,7 +80,8 @@ class ServerResource(ResourceBase):
|
||||
the server version in the format (major, minor, patch, (tag, build))
|
||||
eg (2, 6, 3) for a stable build and (2, 6, 4, 'alpha', 4711) for alpha
|
||||
"""
|
||||
# not tracking as it will be called along with other mutations / queries as a check
|
||||
# not tracking as it will be called along with other mutations / queries
|
||||
# as a check
|
||||
query = gql(
|
||||
"""
|
||||
query Server {
|
||||
|
||||
@@ -76,7 +76,13 @@ class VersionResource(ResourceBase):
|
||||
) -> ResourceCollection[Version]:
|
||||
QUERY = gql(
|
||||
"""
|
||||
query VersionGetVersions($projectId: String!, $modelId: String!, $limit: Int!, $cursor: String, $filter: ModelVersionsFilter) {
|
||||
query VersionGetVersions(
|
||||
$projectId: String!,
|
||||
$modelId: String!,
|
||||
$limit: Int!,
|
||||
$cursor: String,
|
||||
$filter: ModelVersionsFilter
|
||||
) {
|
||||
data:project(id: $projectId) {
|
||||
data:model(id: $modelId) {
|
||||
data:versions(limit: $limit, cursor: $cursor, filter: $filter) {
|
||||
|
||||
@@ -159,11 +159,12 @@ class StreamWrapper:
|
||||
try:
|
||||
self.branch_name = project["project"]["model"]["name"]
|
||||
except KeyError as ke:
|
||||
raise SpeckleException("Project model name is not found", ke)
|
||||
raise SpeckleException("Project model name is not found", ke) from ke
|
||||
|
||||
if not self.stream_id:
|
||||
raise SpeckleException(
|
||||
f"Cannot parse {url} into a stream wrapper class - no {key_stream} id found."
|
||||
f"Cannot parse {url} into a stream wrapper class - no {key_stream} ",
|
||||
"id found.",
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -213,7 +214,11 @@ class StreamWrapper:
|
||||
self._client = SpeckleClient(host=self.host, use_ssl=self.use_ssl)
|
||||
|
||||
if self._account.token is None and token is None:
|
||||
warn(f"No local account found for server {self.host}", SpeckleWarning)
|
||||
warn(
|
||||
f"No local account found for server {self.host}",
|
||||
SpeckleWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._client
|
||||
|
||||
if self._account.token:
|
||||
@@ -266,14 +271,20 @@ class StreamWrapper:
|
||||
if use_fe2 is False or (use_fe2 is True and not self.model_id):
|
||||
base_url = f"{self.server_url}{key_streams}{self.stream_id}"
|
||||
else: # fe2 is True and model_id available
|
||||
base_url = f"{self.server_url}{key_streams}{self.stream_id}{key_branches}{value_branch}"
|
||||
base_url = (
|
||||
f"{self.server_url}{key_streams}"
|
||||
f"{self.stream_id}{key_branches}{value_branch}"
|
||||
)
|
||||
|
||||
if wrapper_type == "object":
|
||||
return f"{base_url}{key_objects}{self.object_id}"
|
||||
elif wrapper_type == "commit":
|
||||
return f"{base_url}{key_commits}{self.commit_id}"
|
||||
elif wrapper_type == "branch":
|
||||
return f"{self.server_url}{key_streams}{self.stream_id}{key_branches}{value_branch}"
|
||||
return (
|
||||
f"{self.server_url}{key_streams}{self.stream_id}"
|
||||
f"{key_branches}{value_branch}"
|
||||
)
|
||||
elif wrapper_type == "stream":
|
||||
return f"{self.server_url}{key_streams}{self.stream_id}"
|
||||
else:
|
||||
|
||||
@@ -99,7 +99,7 @@ def user_application_data_path() -> Path:
|
||||
except Exception as ex:
|
||||
raise SpeckleException(
|
||||
message="Failed to initialize user application data path.", exception=ex
|
||||
)
|
||||
) from ex
|
||||
|
||||
|
||||
def user_speckle_folder_path() -> Path:
|
||||
|
||||
@@ -86,7 +86,8 @@ def track(
|
||||
|
||||
METRICS_TRACKER.queue.put_nowait(event_params)
|
||||
except Exception as ex:
|
||||
# wrapping this whole thing in a try except as we never want a failure here to annoy users!
|
||||
# wrapping this whole thing in a try except as we never want a failure here
|
||||
# to annoy users!
|
||||
LOG.debug(f"Error queueing metrics request: {str(ex)}")
|
||||
|
||||
|
||||
@@ -106,7 +107,7 @@ class Singleton(type):
|
||||
|
||||
def __call__(cls, *args, **kwargs):
|
||||
if cls not in cls._instances:
|
||||
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
|
||||
cls._instances[cls] = super().__call__(*args, **kwargs)
|
||||
return cls._instances[cls]
|
||||
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
|
||||
if isinstance(t, ForwardRef):
|
||||
return True, value
|
||||
|
||||
origin = getattr(t, "__origin__")
|
||||
origin = t.__origin__
|
||||
# below is what in nicer for >= py38
|
||||
# origin = get_origin(t)
|
||||
|
||||
@@ -289,7 +289,7 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
|
||||
if len(args) != len(value):
|
||||
return False, value
|
||||
values = []
|
||||
for t_item, v_item in zip(args, value):
|
||||
for t_item, v_item in zip(args, value, strict=True):
|
||||
item_valid, item_value = _validate_type(t_item, v_item)
|
||||
if not item_valid:
|
||||
return False, value
|
||||
@@ -372,7 +372,8 @@ class Base(_RegisteringBase, speckle_type="Base"):
|
||||
if name == "speckle_type":
|
||||
# not sure if we should raise an exception here??
|
||||
# raise SpeckleException(
|
||||
# "Cannot override the `speckle_type`. This is set manually by the class or on deserialisation"
|
||||
# "Cannot override the `speckle_type`."
|
||||
# "This is set manually by the class or on deserialisation"
|
||||
# )
|
||||
return
|
||||
# if value is not None:
|
||||
@@ -400,7 +401,10 @@ class Base(_RegisteringBase, speckle_type="Base"):
|
||||
try:
|
||||
cls._attr_types = get_type_hints(cls)
|
||||
except Exception as e:
|
||||
warn(f"Could not update forward refs for class {cls.__name__}: {e}")
|
||||
warn(
|
||||
f"Could not update forward refs for class {cls.__name__}: {e}",
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def validate_prop_name(cls, name: str) -> None:
|
||||
@@ -465,7 +469,8 @@ class Base(_RegisteringBase, speckle_type="Base"):
|
||||
|
||||
# @units.setter
|
||||
# def units(self, value: Union[str, Units, None]):
|
||||
# """While this property accepts any string value, geometry expects units to be specific strings (see Units enum)"""
|
||||
# """While this property accepts any string value,
|
||||
# geometry expects units to be specific strings (see Units enum)"""
|
||||
# if isinstance(value, str) or value is None:
|
||||
# self._units = value
|
||||
# elif isinstance(value, Units):
|
||||
|
||||
@@ -23,7 +23,10 @@ class Point(Base, IHasUnits, speckle_type="Objects.Geometry.Point"):
|
||||
z: float
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.__class__.__name__}(x: {self.x}, y: {self.y}, z: {self.z}, units: {self.units})"
|
||||
return (
|
||||
f"{self.__class__.__name__}"
|
||||
f"(x: {self.x}, y: {self.y}, z: {self.z}, units: {self.units})"
|
||||
)
|
||||
|
||||
def to_list(self) -> List[float]:
|
||||
return [self.x, self.y, self.z]
|
||||
@@ -52,8 +55,7 @@ class Point(Base, IHasUnits, speckle_type="Objects.Geometry.Point"):
|
||||
|
||||
# convert other point's coordinates to this point's units
|
||||
scale_factor = get_scale_factor(
|
||||
get_units_from_string(
|
||||
other.units), get_units_from_string(self.units)
|
||||
get_units_from_string(other.units), get_units_from_string(self.units)
|
||||
)
|
||||
|
||||
dx = (other.x * scale_factor) - self.x
|
||||
@@ -94,8 +96,7 @@ class Line(Base, IHasUnits, ICurve, speckle_type="Objects.Geometry.Line"):
|
||||
@classmethod
|
||||
def from_list(cls, coords: List[float], units: str | Units) -> "Line":
|
||||
if len(coords) < 6:
|
||||
raise ValueError(
|
||||
"Line from coordinate array requires 6 coordinates.")
|
||||
raise ValueError("Line from coordinate array requires 6 coordinates.")
|
||||
|
||||
start = Point(x=coords[0], y=coords[1], z=coords[2], units=units)
|
||||
end = Point(x=coords[3], y=coords[4], z=coords[5], units=units)
|
||||
@@ -191,7 +192,7 @@ class Polyline(Base, IHasUnits, ICurve, speckle_type="Objects.Geometry.Polyline"
|
||||
return cls(
|
||||
closed=(int(coords[2]) == 1),
|
||||
domain=Interval(start=coords[3], end=coords[4]),
|
||||
value=coords[6: 6 + point_count],
|
||||
value=coords[6 : 6 + point_count],
|
||||
units=units,
|
||||
)
|
||||
|
||||
@@ -211,7 +212,6 @@ class Mesh(
|
||||
"textureCoordinates": 31250,
|
||||
},
|
||||
):
|
||||
|
||||
vertices: List[float]
|
||||
faces: List[int]
|
||||
colors: List[int] = field(default_factory=list)
|
||||
@@ -226,7 +226,6 @@ class Mesh(
|
||||
return len(self.textureCoordinates) // 2
|
||||
|
||||
def get_point(self, index: int) -> Point:
|
||||
|
||||
index *= 3
|
||||
return Point(
|
||||
x=self.vertices[index],
|
||||
@@ -236,7 +235,6 @@ class Mesh(
|
||||
)
|
||||
|
||||
def get_points(self) -> List[Point]:
|
||||
|
||||
if len(self.vertices) % 3 != 0:
|
||||
raise ValueError(
|
||||
"Mesh vertices list is malformed: expected length to be multiple of 3"
|
||||
@@ -255,12 +253,10 @@ class Mesh(
|
||||
return points
|
||||
|
||||
def get_texture_coordinate(self, index: int) -> Tuple[float, float]:
|
||||
|
||||
index *= 2
|
||||
return (self.textureCoordinates[index], self.textureCoordinates[index + 1])
|
||||
|
||||
def align_vertices_with_texcoords_by_index(self) -> None:
|
||||
|
||||
if not self.textureCoordinates:
|
||||
return
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ class IDisplayValue(Generic[T], metaclass=ABCMeta):
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class IHasUnits(metaclass=ABCMeta):
|
||||
|
||||
units: str | Units
|
||||
_units: str = field(repr=False, init=False)
|
||||
|
||||
@@ -59,7 +58,6 @@ class IHasUnits(metaclass=ABCMeta):
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class IHasArea(metaclass=ABCMeta):
|
||||
|
||||
area: float
|
||||
_area: float = field(init=False, repr=False)
|
||||
|
||||
@@ -69,14 +67,13 @@ class IHasArea(metaclass=ABCMeta):
|
||||
|
||||
@area.setter
|
||||
def area(self, value: float):
|
||||
if not isinstance(value, (int, float)):
|
||||
if not isinstance(value, int | float):
|
||||
raise ValueError(f"Area must be a number, got {type(value)}")
|
||||
self._area = float(value)
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class IHasVolume(metaclass=ABCMeta):
|
||||
|
||||
volume: float
|
||||
_volume: float = field(init=False, repr=False)
|
||||
|
||||
@@ -86,7 +83,7 @@ class IHasVolume(metaclass=ABCMeta):
|
||||
|
||||
@volume.setter
|
||||
def volume(self, value: float):
|
||||
if not isinstance(value, (int, float)):
|
||||
if not isinstance(value, int | float):
|
||||
raise ValueError(f"Volume must be a number, got {type(value)}")
|
||||
self._volume = float(value)
|
||||
|
||||
|
||||
@@ -12,18 +12,25 @@ class Collection(
|
||||
detachable={"elements"},
|
||||
):
|
||||
"""
|
||||
A simple container for organising objects within a model and preserving object hierarchy.
|
||||
A simple container for organising objects within a model
|
||||
and preserving object hierarchy.
|
||||
|
||||
A container is defined by a human-readable name a unique applicationId and its list of contained elements.
|
||||
The elements can include an unrestricted number of Base objects including additional nested Collections.
|
||||
A container is defined by a human-readable name a unique applicationId and
|
||||
its list of contained elements.
|
||||
The elements can include an unrestricted number of Base objects including
|
||||
additional nested Collections.
|
||||
|
||||
Note:
|
||||
A Collection can be for example a Layer in Rhino/AutoCad, a collection in Blender, or a Category in Revit.
|
||||
The location of each collection in the hierarchy of collections in a commit will be retrieved through commit traversal.
|
||||
A Collection can be for example a Layer in Rhino/AutoCad,
|
||||
a collection in Blender, or a Category in Revit.
|
||||
The location of each collection in the hierarchy of collections in a commit
|
||||
will be retrieved through commit traversal.
|
||||
|
||||
Attributes:
|
||||
name: The human-readable name of the Collection. This name is not necessarily unique within a commit. Set the applicationId for a unique identifier.
|
||||
elements: The elements contained in this Collection. This may include additional nested Collections
|
||||
name: The human-readable name of the Collection. This name is not necessarily
|
||||
unique within a commit. Set the applicationId for a unique identifier.
|
||||
elements: The elements contained in this Collection.
|
||||
This may include additional nested Collections
|
||||
"""
|
||||
|
||||
name: str
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Optional
|
||||
|
||||
from specklepy.objects.base import Base
|
||||
@@ -22,7 +22,6 @@ class GroupProxy(
|
||||
speckle_type="Models.Proxies.GroupProxy",
|
||||
detachable={"objects"},
|
||||
):
|
||||
|
||||
objects: List[str]
|
||||
name: str
|
||||
|
||||
@@ -33,7 +32,6 @@ class InstanceProxy(
|
||||
IHasUnits,
|
||||
speckle_type="Models.Proxies.InstanceProxy",
|
||||
):
|
||||
|
||||
definition_id: str
|
||||
transform: List[float]
|
||||
max_depth: int
|
||||
@@ -45,7 +43,6 @@ class InstanceDefinitionProxy(
|
||||
speckle_type="Models.Proxies.InstanceDefinitionProxy",
|
||||
detachable={"objects"},
|
||||
):
|
||||
|
||||
objects: List[str]
|
||||
max_depth: int
|
||||
name: str
|
||||
|
||||
@@ -149,7 +149,7 @@ cube_mesh = Mesh(
|
||||
volume=0.0,
|
||||
)
|
||||
|
||||
print(f"\nMesh Details:")
|
||||
print("\nMesh Details:")
|
||||
print(f"Number of vertices: {cube_mesh.vertices_count}")
|
||||
print(f"Number of texture coordinates: {cube_mesh.texture_coordinates_count}")
|
||||
|
||||
@@ -178,6 +178,5 @@ print("Alignment complete.")
|
||||
|
||||
print(f"Vertices count after alignment: {cube_mesh.vertices_count}")
|
||||
print(
|
||||
f"Texture coordinates count after alignment: {
|
||||
cube_mesh.texture_coordinates_count}"
|
||||
f"Texture coordinates count after alignment: {cube_mesh.texture_coordinates_count}"
|
||||
)
|
||||
|
||||
@@ -19,7 +19,7 @@ from warnings import warn
|
||||
from stringcase import pascalcase
|
||||
|
||||
from specklepy.logging.exceptions import SpeckleException, SpeckleInvalidUnitException
|
||||
from specklepy.objects.units import Units
|
||||
from specklepy.objects_v2.units import Units
|
||||
from specklepy.transports.memory import MemoryTransport
|
||||
|
||||
PRIMITIVES = (int, float, str, bool)
|
||||
@@ -225,7 +225,7 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
|
||||
if isinstance(t, ForwardRef):
|
||||
return True, value
|
||||
|
||||
origin = getattr(t, "__origin__")
|
||||
origin = t.__origin__
|
||||
# below is what in nicer for >= py38
|
||||
# origin = get_origin(t)
|
||||
|
||||
@@ -290,7 +290,7 @@ def _validate_type(t: Optional[type], value: Any) -> Tuple[bool, Any]:
|
||||
if len(args) != len(value):
|
||||
return False, value
|
||||
values = []
|
||||
for t_item, v_item in zip(args, value):
|
||||
for t_item, v_item in zip(args, value, strict=True):
|
||||
item_valid, item_value = _validate_type(t_item, v_item)
|
||||
if not item_valid:
|
||||
return False, value
|
||||
@@ -387,7 +387,8 @@ class Base(_RegisteringBase, speckle_type="Base"):
|
||||
if name == "speckle_type":
|
||||
# not sure if we should raise an exception here??
|
||||
# raise SpeckleException(
|
||||
# "Cannot override the `speckle_type`. This is set manually by the class or on deserialisation"
|
||||
# "Cannot override the `speckle_type`."
|
||||
# "This is set manually by the class or on deserialisation"
|
||||
# )
|
||||
return
|
||||
# if value is not None:
|
||||
@@ -415,7 +416,10 @@ class Base(_RegisteringBase, speckle_type="Base"):
|
||||
try:
|
||||
cls._attr_types = get_type_hints(cls)
|
||||
except Exception as e:
|
||||
warn(f"Could not update forward refs for class {cls.__name__}: {e}")
|
||||
warn(
|
||||
f"Could not update forward refs for class {cls.__name__}: {e}",
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def validate_prop_name(cls, name: str) -> None:
|
||||
@@ -480,7 +484,10 @@ class Base(_RegisteringBase, speckle_type="Base"):
|
||||
|
||||
@units.setter
|
||||
def units(self, value: Union[str, Units, None]):
|
||||
"""While this property accepts any string value, geometry expects units to be specific strings (see Units enum)"""
|
||||
"""
|
||||
While this property accepts any string value,
|
||||
geometry expects units to be specific strings (see Units enum)
|
||||
"""
|
||||
if isinstance(value, str) or value is None:
|
||||
self._units = value
|
||||
elif isinstance(value, Units):
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from enum import Enum
|
||||
from typing import Any, List, Optional
|
||||
|
||||
from specklepy.objects.base import Base
|
||||
from specklepy.objects.encoding import CurveArray, CurveTypeEncoding, ObjectArray
|
||||
from specklepy.objects.primitive import Interval
|
||||
from specklepy.objects.units import get_encoding_from_units, get_units_from_encoding
|
||||
from specklepy.objects_v2.base import Base
|
||||
from specklepy.objects_v2.encoding import CurveArray, CurveTypeEncoding, ObjectArray
|
||||
from specklepy.objects_v2.primitive import Interval
|
||||
from specklepy.objects_v2.units import get_encoding_from_units, get_units_from_encoding
|
||||
|
||||
GEOMETRY = "Objects.Geometry."
|
||||
|
||||
@@ -918,10 +918,12 @@ class Brep(
|
||||
|
||||
self.Vertices = vertices
|
||||
|
||||
# TODO: can this be consistent with loops, edges, faces, curves, etc and prepend with the chunk list? needs to happen in sharp first
|
||||
# TODO: can this be consistent with loops, edges, faces, curves,
|
||||
# etc and prepend with the chunk list? needs to happen in sharp first
|
||||
@property
|
||||
def TrimsValue(self) -> List[float]:
|
||||
# return None if self.Trims is None else ObjectArray.from_objects(self.Trims).data
|
||||
# return None if self.Trims is None else
|
||||
# ObjectArray.from_objects(self.Trims).data
|
||||
if not self.Trims:
|
||||
return
|
||||
value = []
|
||||
|
||||
@@ -58,9 +58,7 @@ class CommitObjectBuilder(ABC, Generic[T]):
|
||||
if parent_id == ROOT:
|
||||
parent = root_commit_object
|
||||
else:
|
||||
parent = (
|
||||
self.converted[parent_id] if parent_id in self.converted else None
|
||||
)
|
||||
parent = self.converted.get(parent_id, None)
|
||||
|
||||
if not parent:
|
||||
continue
|
||||
@@ -74,13 +72,15 @@ class CommitObjectBuilder(ABC, Generic[T]):
|
||||
elements.append(current)
|
||||
return
|
||||
except Exception as ex:
|
||||
# A parent was found, but it was invalid (Likely because of a type mismatch on a `elements` property)
|
||||
# A parent was found, but it was invalid
|
||||
# (Likely because of a type mismatch on a `elements` property)
|
||||
print(
|
||||
f"Failed to add object {type(current)} to a converted parent; {ex}"
|
||||
)
|
||||
|
||||
raise Exception(
|
||||
f"Could not find a valid parent for object of type {type(current)}. Checked {len(parents)} potential parent, and non were converted!"
|
||||
f"Could not find a valid parent for object of type {type(current)}."
|
||||
f"Checked {len(parents)} potential parent, and non were converted!"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -58,12 +58,16 @@ class GraphTraversal:
|
||||
for child_prop in members_to_traverse:
|
||||
try:
|
||||
if child_prop in {"speckle_type", "units", "applicationId"}:
|
||||
continue # debug: to avoid noisy exceptions, explicitly avoid checking ones we know will fail, this is not exhaustive
|
||||
# debug: to avoid noisy exceptions,
|
||||
# explicitly avoid checking ones we know will fail,
|
||||
# this is not exhaustive
|
||||
continue
|
||||
if getattr(current, child_prop, None):
|
||||
value = current[child_prop]
|
||||
self._traverse_member_to_stack(stack, value, child_prop, head)
|
||||
except KeyError:
|
||||
# Unset application ids, and class variables like SpeckleType will throw when __getitem__ is called
|
||||
# Unset application ids, and class variables like SpeckleType will
|
||||
# throw when __getitem__ is called
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
@@ -119,7 +123,4 @@ class TraversalRule:
|
||||
return set(self._members_to_traverse(o))
|
||||
|
||||
def does_rule_hold(self, o: Base) -> bool:
|
||||
for condition in self._conditions:
|
||||
if condition(o):
|
||||
return True
|
||||
return False
|
||||
return any(condition(o) for condition in self._conditions)
|
||||
|
||||
@@ -30,6 +30,7 @@ def safe_json_loads(obj: str, obj_id=None) -> Any:
|
||||
f"Failed to deserialise object (id: {obj_id}). This is likely a ujson big"
|
||||
f" int error - falling back to json. \nError: {err}",
|
||||
SpeckleWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return json.loads(obj)
|
||||
|
||||
@@ -140,7 +141,8 @@ class BaseObjectSerializer:
|
||||
object_builder[prop] = value
|
||||
continue
|
||||
|
||||
# NOTE: for dynamic props, this won't be re-serialised as an enum but as an int
|
||||
# NOTE: for dynamic props, this won't be re-serialised
|
||||
# as an enum but as an int
|
||||
if isinstance(value, Enum):
|
||||
object_builder[prop] = value.value
|
||||
continue
|
||||
@@ -222,7 +224,7 @@ class BaseObjectSerializer:
|
||||
if isinstance(obj, Enum):
|
||||
return obj.value
|
||||
|
||||
elif isinstance(obj, (list, tuple, set)):
|
||||
elif isinstance(obj, list | tuple | set):
|
||||
if not detach:
|
||||
return [self.traverse_value(o) for o in obj]
|
||||
|
||||
@@ -257,6 +259,7 @@ class BaseObjectSerializer:
|
||||
f"Failed to handle {type(obj)} in"
|
||||
" `BaseObjectSerializer.traverse_value`",
|
||||
SpeckleWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
return str(obj)
|
||||
@@ -374,6 +377,7 @@ class BaseObjectSerializer:
|
||||
f"Could not find the referenced child object of id `{ref_id}`"
|
||||
f" in the given read transport: {self.read_transport.name}",
|
||||
SpeckleWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
base.__setattr__(prop, self.handle_value(value))
|
||||
|
||||
@@ -437,6 +441,7 @@ class BaseObjectSerializer:
|
||||
f"Could not find the referenced child object of id `{ref_id}` in the"
|
||||
f" given read transport: {self.read_transport.name}",
|
||||
SpeckleWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return obj
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ class MemoryTransport(AbstractTransport):
|
||||
) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
def get_object(self, id: str) -> str or None:
|
||||
return self.objects[id] if id in self.objects else None
|
||||
def get_object(self, id: str) -> str | None:
|
||||
return self.objects.get(id, None)
|
||||
|
||||
def has_objects(self, id_list: List[str]) -> Dict[str, bool]:
|
||||
return {id: (id in self.objects) for id in id_list}
|
||||
|
||||
@@ -11,7 +11,7 @@ from specklepy.logging.exceptions import SpeckleException
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BatchSender(object):
|
||||
class BatchSender:
|
||||
def __init__(
|
||||
self,
|
||||
server_url,
|
||||
@@ -123,8 +123,14 @@ class BatchSender(object):
|
||||
upload_data = "[" + ",".join(new_objects) + "]"
|
||||
upload_data_gzip = gzip.compress(upload_data.encode())
|
||||
LOG.info(
|
||||
"Uploading batch of %s objects (%s new): (size: %s, compressed size: %s)"
|
||||
% (len(batch), len(new_objects), len(upload_data), len(upload_data_gzip))
|
||||
"Uploading batch of {batch_size} objects {new_object_count}: ",
|
||||
"(size: {upload_size}, compressed size: {upload_data_size})",
|
||||
{
|
||||
"batch_size": len(batch),
|
||||
"new_object_count": len(new_objects),
|
||||
"upload_size": len(upload_data),
|
||||
"upload_data_size": len(upload_data_gzip),
|
||||
},
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -74,7 +74,8 @@ class ServerTransport(AbstractTransport):
|
||||
SpeckleWarning(
|
||||
"Unauthenticated Speckle Client provided to Server Transport"
|
||||
f" for {url}. Receiving from private streams will fail."
|
||||
)
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
else:
|
||||
self.account = client.account
|
||||
|
||||
@@ -39,8 +39,7 @@ class SQLiteTransport(AbstractTransport):
|
||||
f"SQLiteTransport could not initialise {self.scope}.db at"
|
||||
f" {self._base_path}. Either provide a different `base_path` or use an"
|
||||
" alternative transport.",
|
||||
ex,
|
||||
)
|
||||
) from ex
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"SQLiteTransport(app: '{self.app_name}', scope: '{self.scope}')"
|
||||
@@ -105,10 +104,9 @@ class SQLiteTransport(AbstractTransport):
|
||||
raise SpeckleException(
|
||||
"Could not save the batch of objects to the local db. Inner exception:"
|
||||
f" {ex}",
|
||||
ex,
|
||||
)
|
||||
) from ex
|
||||
|
||||
def get_object(self, id: str) -> str or None:
|
||||
def get_object(self, id: str) -> str | None:
|
||||
self.__check_connection()
|
||||
with closing(self.__connection.cursor()) as c:
|
||||
row = c.execute(
|
||||
|
||||
@@ -45,7 +45,8 @@ class TestActiveUserResource:
|
||||
|
||||
def test_active_user_get_projects_with_filter(self, client: SpeckleClient):
|
||||
# Since the client may be reused for other tests,
|
||||
# this test does rely on no other test creating a project with "Search for me" in its name
|
||||
# this test does rely on no other test creating a project
|
||||
# with "Search for me" in its name
|
||||
p1 = client.project.create(
|
||||
ProjectCreateInput(name="Search for me!", description=None, visibility=None)
|
||||
)
|
||||
|
||||
@@ -33,8 +33,8 @@ class TestOtherUser:
|
||||
assert isinstance(fetched_user, LimitedUser)
|
||||
assert fetched_user.name == second_user_dict["name"]
|
||||
# changed in the server, now you cannot get emails of other users
|
||||
# not checking this, since the first user could or could not be an admin on the server
|
||||
# admins can get emails of others, regular users can't
|
||||
# not checking this, since the first user could or could not be an admin
|
||||
# on the server, admins can get emails of others, regular users can't
|
||||
# assert fetched_user.email == None
|
||||
|
||||
second_user_dict["id"] = fetched_user.id
|
||||
|
||||
@@ -36,8 +36,8 @@ class TestUser:
|
||||
assert isinstance(fetched_user, User)
|
||||
assert fetched_user.name == second_user_dict["name"]
|
||||
# changed in the server, now you cannot get emails of other users
|
||||
# not checking this, since the first user could or could not be an admin on the server
|
||||
# admins can get emails of others, regular users can't
|
||||
# not checking this, since the first user could or could not be an admin
|
||||
# on the server, admins can get emails of others, regular users can't
|
||||
# assert fetched_user.email == None
|
||||
|
||||
second_user_dict["id"] = fetched_user.id
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import contextlib
|
||||
import json
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
@@ -16,14 +17,11 @@ def user_path() -> Iterable[Path]:
|
||||
speckle_path_provider.override_application_data_path(tempfile.gettempdir())
|
||||
path = speckle_path_provider.accounts_folder_path().joinpath("test_acc.json")
|
||||
# hey, py37 doesn't support the missing_ok argument
|
||||
try:
|
||||
with contextlib.suppress(Exception):
|
||||
path.unlink()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
|
||||
with contextlib.suppress(Exception):
|
||||
path.unlink(missing_ok=True)
|
||||
except Exception:
|
||||
pass
|
||||
path.parent.absolute().mkdir(exist_ok=True)
|
||||
yield path
|
||||
if path.exists():
|
||||
@@ -34,7 +32,7 @@ def user_path() -> Iterable[Path]:
|
||||
def test_parse_empty():
|
||||
try:
|
||||
StreamWrapper("https://testing.speckle.dev/streams")
|
||||
assert False
|
||||
raise AssertionError()
|
||||
except SpeckleException:
|
||||
assert True
|
||||
|
||||
@@ -42,7 +40,7 @@ def test_parse_empty():
|
||||
def test_parse_empty_fe2():
|
||||
try:
|
||||
StreamWrapper("https://latest.speckle.systems/projects")
|
||||
assert False
|
||||
raise AssertionError()
|
||||
except SpeckleException:
|
||||
assert True
|
||||
|
||||
@@ -169,7 +167,7 @@ def test_parse_model():
|
||||
def test_parse_federated_model():
|
||||
try:
|
||||
StreamWrapper("https://latest.speckle.systems/projects/843d07eb10/models/$main")
|
||||
assert False
|
||||
raise AssertionError()
|
||||
except SpeckleException:
|
||||
assert True
|
||||
|
||||
@@ -179,7 +177,7 @@ def test_parse_multi_model():
|
||||
StreamWrapper(
|
||||
"https://latest.speckle.systems/projects/2099ac4b5f/models/1870f279e3,a9cfdddc79"
|
||||
)
|
||||
assert False
|
||||
raise AssertionError()
|
||||
except SpeckleException:
|
||||
assert True
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ import pytest
|
||||
|
||||
from specklepy.api import operations
|
||||
from specklepy.logging.exceptions import SpeckleException, SpeckleInvalidUnitException
|
||||
from specklepy.objects.base import Base
|
||||
from specklepy.objects.units import Units
|
||||
from specklepy.objects_v2.base import Base
|
||||
from specklepy.objects_v2.units import Units
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
||||
@@ -6,8 +6,8 @@ import pytest
|
||||
from specklepy.api import operations
|
||||
from specklepy.logging.exceptions import SpeckleException
|
||||
from specklepy.objects.base import Base
|
||||
from specklepy.objects.encoding import CurveArray, ObjectArray
|
||||
from specklepy.objects.geometry import (
|
||||
from specklepy.objects_v2.encoding import CurveArray, ObjectArray
|
||||
from specklepy.objects_v2.geometry import (
|
||||
Arc,
|
||||
Box,
|
||||
Brep,
|
||||
@@ -30,7 +30,7 @@ from specklepy.objects.geometry import (
|
||||
Surface,
|
||||
Vector,
|
||||
)
|
||||
from specklepy.objects.units import Units
|
||||
from specklepy.objects_v2.units import Units
|
||||
from specklepy.transports.memory import MemoryTransport
|
||||
|
||||
|
||||
@@ -508,7 +508,7 @@ def test_serialized_brep_attributes(brep: Brep):
|
||||
]
|
||||
|
||||
for k in removed_keys:
|
||||
assert k not in serialized_dict.keys()
|
||||
assert k not in serialized_dict
|
||||
|
||||
|
||||
def test_mesh_create():
|
||||
|
||||
@@ -2,8 +2,8 @@ from dataclasses import dataclass
|
||||
from typing import Dict, List, Optional
|
||||
from unittest import TestCase
|
||||
|
||||
from specklepy.objects import Base
|
||||
from specklepy.objects.graph_traversal.traversal import GraphTraversal, TraversalRule
|
||||
from specklepy.objects_v2 import Base
|
||||
from specklepy.objects_v2.graph_traversal.traversal import GraphTraversal, TraversalRule
|
||||
|
||||
|
||||
@dataclass()
|
||||
|
||||
@@ -2,8 +2,8 @@ from typing import Type
|
||||
|
||||
import pytest
|
||||
|
||||
from specklepy.objects.base import Base
|
||||
from specklepy.objects.structural import Concrete
|
||||
from specklepy.objects_v2.base import Base
|
||||
from specklepy.objects_v2.structural import Concrete
|
||||
|
||||
|
||||
class Foo(Base):
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import pytest
|
||||
|
||||
from specklepy.objects.geometry import Line, Mesh, Point, Vector
|
||||
from specklepy.objects.structural.analysis import Model
|
||||
from specklepy.objects.structural.geometry import (
|
||||
from specklepy.objects_v2.geometry import Line, Mesh, Point, Vector
|
||||
from specklepy.objects_v2.structural.analysis import Model
|
||||
from specklepy.objects_v2.structural.geometry import (
|
||||
Element1D,
|
||||
Element2D,
|
||||
ElementType1D,
|
||||
@@ -10,9 +10,9 @@ from specklepy.objects.structural.geometry import (
|
||||
Node,
|
||||
Restraint,
|
||||
)
|
||||
from specklepy.objects.structural.loading import LoadGravity
|
||||
from specklepy.objects.structural.materials import StructuralMaterial
|
||||
from specklepy.objects.structural.properties import (
|
||||
from specklepy.objects_v2.structural.loading import LoadGravity
|
||||
from specklepy.objects_v2.structural.materials import StructuralMaterial
|
||||
from specklepy.objects_v2.structural.properties import (
|
||||
MemberType,
|
||||
Property1D,
|
||||
Property2D,
|
||||
|
||||
@@ -3,8 +3,8 @@ from typing import List
|
||||
import pytest
|
||||
|
||||
from specklepy.api import operations
|
||||
from specklepy.objects.geometry import Point, Vector
|
||||
from specklepy.objects.other import Transform
|
||||
from specklepy.objects_v2.geometry import Point, Vector
|
||||
from specklepy.objects_v2.other import Transform
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import List
|
||||
|
||||
from specklepy.objects.base import Base
|
||||
from specklepy.objects_v2.base import Base
|
||||
from specklepy.serialization.base_object_serializer import BaseObjectSerializer
|
||||
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ from typing import Any, Dict, List, Optional, Set, Tuple, Union
|
||||
|
||||
import pytest
|
||||
|
||||
from specklepy.objects.base import Base, _validate_type
|
||||
from specklepy.objects.primitive import Interval
|
||||
from specklepy.objects_v2.base import Base, _validate_type
|
||||
from specklepy.objects_v2.primitive import Interval
|
||||
|
||||
test_base = Base()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from specklepy.objects.units import Units, get_scale_factor
|
||||
from specklepy.objects_v2.units import Units, get_scale_factor
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
||||
+9
-5
@@ -67,7 +67,7 @@ def user_application_data_path() -> Path:
|
||||
else:
|
||||
return _ensure_folder_exists(Path.home(), ".config")
|
||||
except Exception as ex:
|
||||
raise Exception("Failed to initialize user application data path.", ex)
|
||||
raise Exception("Failed to initialize user application data path.") from ex
|
||||
|
||||
|
||||
def user_speckle_folder_path() -> Path:
|
||||
@@ -162,7 +162,10 @@ def install_requirements(host_application: str) -> None:
|
||||
)
|
||||
|
||||
if completed_process.returncode != 0:
|
||||
m = f"Failed to install dependenices through pip, got {completed_process.returncode} return code"
|
||||
m = (
|
||||
"Failed to install dependenices through pip, got ",
|
||||
f"{completed_process.returncode} return code",
|
||||
)
|
||||
print(m)
|
||||
raise Exception(m)
|
||||
|
||||
@@ -197,7 +200,8 @@ def ensure_dependencies(host_application: str) -> None:
|
||||
invalidate_caches()
|
||||
_import_dependencies()
|
||||
print("Successfully found dependencies")
|
||||
except ImportError:
|
||||
except ImportError as e:
|
||||
raise Exception(
|
||||
f"Cannot automatically ensure Speckle dependencies. Please try restarting the host application {host_application}!"
|
||||
)
|
||||
"Cannot automatically ensure Speckle dependencies.",
|
||||
f"Please try restarting the host application {host_application}!",
|
||||
) from e
|
||||
|
||||
Reference in New Issue
Block a user