4 Commits

Author SHA1 Message Date
Gergő Jedlicska daf7827585 bump dependencies (#88)
* bump dependencies

* chore: bump python in more places
2025-11-18 19:11:39 +01:00
dependabot[bot] 64a9b94d50 chore(deps): bump actions/checkout from 4.1.7 to 5.0.0 (#59)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.7 to 5.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4.1.7...v5.0.0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-04 11:43:52 +00:00
Björn Steinhagen 4bcf005f4a chore(deps): drop poetry as a dependency in the python automate template (#40)
* chore: bump specklepy

* refactor: requirements files

* refactor: dockerfile

* refactor: update GitHub actions

* refactor: update devcontainer config

* docs: updated `README`

* docs: better explanations

* docs: wording

* chore: dependabot config

* docs: keeping things in sync

* fix: skip pip upgrade

* refactor: updated devcontainer

* refactor: toml instead of requirements

* refactor: update docker

* docs: updated `README`

* chore: classifiers does nothing

* chore: wrap up the v3 transition

---------

Co-authored-by: Gergő Jedlicska <gergo@jedlicska.com>
2025-06-03 13:29:18 +02:00
Gergő Jedlicska cf3a8f4267 chore: bump specklepy (#39) 2025-03-27 16:45:37 +01:00
12 changed files with 147 additions and 1461 deletions
+2 -5
View File
@@ -4,9 +4,6 @@
"name": "Python 3",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/python:1-3.11-bullseye",
"features": {
"ghcr.io/devcontainers-contrib/features/poetry:2": {}
},
"remoteEnv": {
"SPECKLE_TOKEN": "foobar"
@@ -22,7 +19,7 @@
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "cp .env.example .env && POETRY_VIRTUALENVS_IN_PROJECT=true poetry install --no-root",
"postCreateCommand": "cp .env.example .env && python -m venv .venv && . .venv/bin/activate && pip install --upgrade pip && pip install .[dev]",
// Configure tool-specific properties.
"customizations": {
@@ -40,4 +37,4 @@
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
}
+4
View File
@@ -4,3 +4,7 @@ updates:
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
+7 -12
View File
@@ -1,9 +1,9 @@
name: 'build and deploy Speckle functions'
name: "build and deploy Speckle functions"
on:
workflow_dispatch:
push:
tags:
- '*'
- "*"
jobs:
publish-automate-function-version: # make sure the action works on a clean machine without building
@@ -11,18 +11,13 @@ jobs:
FUNCTION_SCHEMA_FILE_NAME: functionSchema.json
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.1.7
- uses: actions/checkout@v5.0.0
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install poetry
python-version: "3.13"
- name: Install dependencies
run: |
pip install poetry==1.8.4 &&
poetry config virtualenvs.create false &&
poetry config virtualenvs.in-project false &&
poetry config installer.parallel true
- name: Restore dependencies
run: poetry install --no-root
pip install .[dev]
- name: Extract functionInputSchema
id: extract_schema
run: |
@@ -34,4 +29,4 @@ jobs:
speckle_token: ${{ secrets.SPECKLE_FUNCTION_TOKEN }}
speckle_function_id: ${{ secrets.SPECKLE_FUNCTION_ID }}
speckle_function_input_schema_file_path: ${{ env.FUNCTION_SCHEMA_FILE_NAME }}
speckle_function_command: 'python -u main.py run'
speckle_function_command: "python -u main.py run"
+7 -7
View File
@@ -1,16 +1,16 @@
# We use the official Python 3.11 image as our base image and will add our code to it. For more details, see https://hub.docker.com/_/python
FROM python:3.11-slim
# We install poetry to generate a list of dependencies which will be required by our application
RUN pip install poetry==1.8.4
FROM python:3.13-slim
# We set the working directory to be the /home/speckle directory; all of our files will be copied here.
WORKDIR /home/speckle
# Copy pyproject.toml first to leverage Docker layer caching
COPY pyproject.toml /home/speckle/
# Install the required Python packages (production dependencies only)
RUN pip install --no-cache-dir .
# Copy all of our code and assets from the local directory into the /home/speckle directory of the container.
# We also ensure that the user 'speckle' owns these files, so it can access them
# This assumes that the Dockerfile is in the same directory as the rest of the code
COPY . /home/speckle
# Using poetry, we generate a list of requirements, save them to requirements.txt, and then use pip to install them
RUN poetry export --format requirements.txt --output /home/speckle/requirements.txt && pip install --requirement /home/speckle/requirements.txt
+83 -9
View File
@@ -9,19 +9,49 @@ It also has some sane defaults for development environment setups.
## Getting started
1. Use this template repository to create a new repository in your own / organization's profile.
Register the function
1. Register the function
### Add new dependencies
To add new Python package dependencies to the project, use the following:
`$ poetry add pandas`
To add new Python package dependencies to the project, edit the `pyproject.toml` file:
**For packages your function needs to run** (like pandas, requests, etc.):
```toml
dependencies = [
"specklepy==3.0.0",
"pandas==2.1.0", # Add production dependencies here
]
```
**For development tools** (like testing or formatting tools):
```toml
[project.optional-dependencies]
dev = [
"black==23.12.1",
"pytest-mock==3.11.1", # Add development dependencies here
# ... other dev tools
]
```
**How to decide which section?**
- If your `main.py` (or other function logic) imports it → `dependencies`
- If it's just a tool to help you code → `[project.optional-dependencies].dev`
Example:
```python
# In your main.py
import pandas as pd # ← This goes in dependencies
import specklepy # ← This goes in dependencies
# You won't import these in main.py:
# pytest, black, mypy ← These go in [project.optional-dependencies].dev
```
### Change launch variables
Describe how the launch.json should be edited.
### Github Codespaces
### GitHub Codespaces
Create a new repo from this template, and use the create new code.
@@ -43,13 +73,57 @@ Create a new repo from this template, and use the create new code.
## Developer Requirements
1. Install the following:
- [Python 3](https://www.python.org/downloads/)
- [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
1. Run `poetry shell && poetry install` to install the required Python packages.
- [Python 3.11+](https://www.python.org/downloads/)
1. Run the following to set up your development environment:
```bash
python -m venv .venv
# On Windows
.venv\Scripts\activate
# On macOS/Linux
source .venv/bin/activate
pip install --upgrade pip
pip install .[dev]
```
**What this installs:**
- All the packages your function needs to run (`dependencies`)
- Plus development tools like testing and code formatting (`[project.optional-dependencies].dev`)
**Why separate sections?**
- `dependencies`: Only what gets deployed with your function (lightweight)
- `dev` dependencies: Extra tools to help you write better code locally
## Building and Testing
The code can be tested locally by running `poetry run pytest`.
The code can be tested locally by running `pytest`.
### Alternative dependency managers
This template uses the modern **PEP 621** standard in `pyproject.toml`, which works with all modern Python dependency managers:
#### Using Poetry
```bash
poetry install # Automatically reads pyproject.toml
```
#### Using uv
```bash
uv sync # Automatically reads pyproject.toml
```
#### Using pip-tools
```bash
pip-compile pyproject.toml # Generate requirements.txt from pyproject.toml
pip install -r requirements.txt
```
#### Using pdm
```bash
pdm install # Automatically reads pyproject.toml
```
**Advantage**: All tools read the same `pyproject.toml` file, so there's no need to keep multiple files in sync!
### Building and running the Docker Container Image
+4 -4
View File
@@ -7,8 +7,8 @@ from specklepy.objects import Base
def flatten_base(base: Base) -> Iterable[Base]:
"""Flatten a base object into an iterable of bases.
This function recursively traverses the `elements` or `@elements` attribute of the
This function recursively traverses the `elements` or `@elements` attribute of the
base object, yielding each nested base object.
Args:
@@ -19,9 +19,9 @@ def flatten_base(base: Base) -> Iterable[Base]:
"""
# Attempt to get the elements attribute, fallback to @elements if necessary
elements = getattr(base, "elements", getattr(base, "@elements", None))
if elements is not None:
for element in elements:
yield from flatten_base(element)
yield base
+2 -2
View File
@@ -42,7 +42,7 @@ def automate_function(
automate_context: A context-helper object that carries relevant information
about the runtime context of this function.
It gives access to the Speckle project data that triggered this run.
It also has convenient methods for attaching result data to the Speckle model.
It also has convenient methods for attaching results to the Speckle model.
function_inputs: An instance object matching the defined schema.
"""
# The context provides a convenient way to receive the triggering version.
@@ -60,7 +60,7 @@ def automate_function(
automate_context.attach_error_to_objects(
category="Forbidden speckle_type"
f" ({function_inputs.forbidden_speckle_type})",
object_ids=[o.id for o in objects_with_forbidden_speckle_type if o.id],
affected_objects=objects_with_forbidden_speckle_type,
message="This project should not contain the type: "
f"{function_inputs.forbidden_speckle_type}",
)
+2
View File
@@ -0,0 +1,2 @@
[tools]
python = '3.13'
Generated
-1389
View File
File diff suppressed because it is too large Load Diff
+30 -28
View File
@@ -1,35 +1,37 @@
[tool.poetry]
name = "speckle-automate-py"
[project]
name = "speckle-automate-function"
version = "0.1.0"
description = "Example function for Speckle Automate using specklepy"
authors = ["Gergő Jedlicska <gergo@jedlicska.com>"]
requires-python = ">=3.13"
authors = [{ name = "Speckle Systems", email = "hello@speckle.systems" }]
maintainers = [{ name = "Speckle Systems", email = "hello@speckle.systems" }]
description = "A Speckle Automate function template using specklepy"
readme = "README.md"
package-mode = false
license = "Apache-2.0"
keywords = ["speckle", "automate", "bim", "aec"]
[tool.poetry.dependencies]
python = "^3.11"
specklepy = "^2.21.0"
dependencies = ["specklepy==3.1.0"]
[tool.poetry.group.dev.dependencies]
black = "^23.3.0"
mypy = "^1.3.0"
ruff = "^0.0.271"
pydantic-settings = "^2.3.0"
pytest = "^7.4.2"
# specklepy = { path = "../specklepy", develop = true }
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.ruff]
select = [
"E", # pycodestyle
"F", # pyflakes
"UP", # pyupgrade
"D", # pydocstyle
"I", # isort
[project.optional-dependencies]
dev = [
"mypy==1.13.0",
"pytest==7.4.4",
"ruff==0.11.12",
]
[tool.ruff.pydocstyle]
[tool.ruff]
exclude = [".venv", "**/*.yml"]
[tool.ruff.lint]
select = [
"E", # pycodestyle
"F", # pyflakes
"UP", # pyupgrade
"D", # pydocstyle
"I", # isort
]
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.setuptools]
py-modules = []
+1
View File
@@ -0,0 +1 @@
"""Tests for the automate function."""
+5 -5
View File
@@ -1,20 +1,20 @@
"""Run integration tests with a speckle server."""
from pydantic import SecretStr
from speckle_automate import (
AutomationContext,
AutomationRunData,
AutomationStatus,
run_function
run_function,
)
from speckle_automate.fixtures import * # noqa: F403
from main import FunctionInputs, automate_function
from speckle_automate.fixtures import *
def test_function_run(test_automation_run_data: AutomationRunData, test_automation_token: str):
def test_function_run(
test_automation_run_data: AutomationRunData, test_automation_token: str
):
"""Run an integration test for the automate function."""
automation_context = AutomationContext.initialize(
test_automation_run_data, test_automation_token