Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 32c30bc59b |
@@ -4,6 +4,9 @@
|
||||
"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"
|
||||
@@ -19,7 +22,7 @@
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "cp .env.example .env && python -m venv .venv && . .venv/bin/activate && pip install --upgrade pip && pip install .[dev]",
|
||||
"postCreateCommand": "cp .env.example .env && POETRY_VIRTUALENVS_IN_PROJECT=true poetry install --no-root",
|
||||
|
||||
// Configure tool-specific properties.
|
||||
"customizations": {
|
||||
@@ -37,4 +40,4 @@
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,3 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
@@ -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
|
||||
@@ -12,16 +12,24 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.7
|
||||
- uses: actions/setup-python@v6
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- name: Install dependencies
|
||||
python-version: '3.11'
|
||||
- name: Install poetry
|
||||
run: |
|
||||
pip install .[dev]
|
||||
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
|
||||
- name: Extract functionInputSchema
|
||||
id: extract_schema
|
||||
run: |
|
||||
python main.py generate_schema ${HOME}/${{ env.FUNCTION_SCHEMA_FILE_NAME }}
|
||||
python main.py generate_schema "${HOME}/${{ env.FUNCTION_SCHEMA_FILE_NAME }}"
|
||||
echo "Checking if functionSchema.json exists after generation..."
|
||||
ls -lah "${HOME}/${{ env.FUNCTION_SCHEMA_FILE_NAME }}"
|
||||
|
||||
- name: Speckle Automate Function - Build and Publish
|
||||
uses: specklesystems/speckle-automate-github-composite-action@0.8.1
|
||||
with:
|
||||
@@ -29,4 +37,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
@@ -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
|
||||
|
||||
# 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
|
||||
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
|
||||
|
||||
@@ -9,49 +9,19 @@ 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.
|
||||
1. Register the function
|
||||
|
||||
Register the function
|
||||
|
||||
### Add new dependencies
|
||||
|
||||
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
|
||||
```
|
||||
To add new Python package dependencies to the project, use the following:
|
||||
`$ poetry add pandas`
|
||||
|
||||
### 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.
|
||||
|
||||
@@ -73,57 +43,13 @@ Create a new repo from this template, and use the create new code.
|
||||
## Developer Requirements
|
||||
|
||||
1. Install the following:
|
||||
- [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
|
||||
- [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.
|
||||
|
||||
## Building and Testing
|
||||
|
||||
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!
|
||||
The code can be tested locally by running `poetry run pytest`.
|
||||
|
||||
### Building and running the Docker Container Image
|
||||
|
||||
|
||||
+4
-4
@@ -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
|
||||
|
||||
@@ -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 results to the Speckle model.
|
||||
It also has convenient methods for attaching result data 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})",
|
||||
affected_objects=objects_with_forbidden_speckle_type,
|
||||
object_ids=[o.id for o in objects_with_forbidden_speckle_type if o.id],
|
||||
message="This project should not contain the type: "
|
||||
f"{function_inputs.forbidden_speckle_type}",
|
||||
)
|
||||
|
||||
Generated
+1389
File diff suppressed because it is too large
Load Diff
+25
-27
@@ -1,37 +1,35 @@
|
||||
[project]
|
||||
name = "speckle-automate-function"
|
||||
[tool.poetry]
|
||||
name = "speckle-automate-py"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.11"
|
||||
authors = [{ name = "Speckle Systems", email = "hello@speckle.systems" }]
|
||||
maintainers = [{ name = "Speckle Systems", email = "hello@speckle.systems" }]
|
||||
description = "A Speckle Automate function template using specklepy"
|
||||
description = "Example function for Speckle Automate using specklepy"
|
||||
authors = ["Gergő Jedlicska <gergo@jedlicska.com>"]
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0"
|
||||
keywords = ["speckle", "automate", "bim", "aec"]
|
||||
package-mode = false
|
||||
|
||||
dependencies = ["specklepy==3.0.0"]
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.11"
|
||||
specklepy = "^2.21.0"
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"mypy==1.13.0",
|
||||
"pytest==7.4.4",
|
||||
"ruff==0.11.12",
|
||||
]
|
||||
[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]
|
||||
exclude = [".venv", "**/*.yml"]
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = [
|
||||
"E", # pycodestyle
|
||||
"F", # pyflakes
|
||||
"UP", # pyupgrade
|
||||
"D", # pydocstyle
|
||||
"I", # isort
|
||||
"E", # pycodestyle
|
||||
"F", # pyflakes
|
||||
"UP", # pyupgrade
|
||||
"D", # pydocstyle
|
||||
"I", # isort
|
||||
]
|
||||
|
||||
[tool.ruff.lint.pydocstyle]
|
||||
[tool.ruff.pydocstyle]
|
||||
convention = "google"
|
||||
|
||||
[tool.setuptools]
|
||||
py-modules = []
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
"""Tests for the automate function."""
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user