Skip to content

Commit a691552

Browse files
Initial public release
0 parents  commit a691552

File tree

665 files changed

+84238
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

665 files changed

+84238
-0
lines changed

.githooks/pre-commit

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
# format easily fixable things
4+
make format
5+
make lint-fix
6+
7+
# ensure no linting errors
8+
make lint
9+
10+
# Check if any files were modified
11+
if ! git diff --quiet; then
12+
echo "Staging formatted changes..."
13+
git add -u
14+
fi

.github/copilot-instructions.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Python coding guidelines
2+
3+
## General guidelines
4+
5+
When importing, import classes directly. For functions, import the containing module and call the function using dot notation.
6+
7+
Inside each file, put public classes then public functions, then private classes, and finally private functions.
8+
9+
For todos, use a format `# TODO({Name}, {month}/{year}): {full_sentence_comment}`, e.g. `# TODO(Michal, 08/2023): Address in the next PR.`.
10+
11+
If using docstrings, use the google style guide and triple quotes. Use `Args:` and `Returns:` sections. Don't repeat the type in the description.
12+
Any example:
13+
```python
14+
def foo(bar: int) -> str:
15+
"""Converts an integer to a string.
16+
17+
Args:
18+
bar: The bar to convert.
19+
20+
Returns:
21+
The converted bar.
22+
"""
23+
return str(bar)
24+
```
25+
26+
For comments outside of docstrings, use full sentences and proper punctuation.
27+
E.g. `# This is a comment.` instead of `# this is a comment`.
28+
29+
Avoid using `assert` outside of tests.
30+
31+
Always use keyword arguments when calling functions, except for single-argument functions.
32+
33+
Don't care about formatting, we use ruff for that.
34+
35+
## Typing
36+
37+
Always use type hints, such that mypy passes.
38+
39+
Use newer syntax e.g. `list[int | None]` instead of `List[Optional[int]]`. When needing them, add `from __future__ import annotations` at the top of the file.
40+
41+
Use abstract inputs and concrete outputs. See this example:
42+
```python
43+
def add_suffix_to_list(lst: Sequence[str], suffix: str) -> list[str]:
44+
return [x + suffix for x in lst]
45+
```
46+
47+
Use Sequence and Mapping instead of list and dict for immutable types. Import them from `collections.abc`.
48+
49+
Be specific when ignoring type errors, e.g. `# type: ignore[no-untyped-call]` instead of `# type: ignore`.
50+
51+
## Testing
52+
53+
Always use pytest, never unittest.
54+
55+
When testing a class named `MyClass`, put all tests under a class named `TestMyClass`.
56+
57+
When testing a function or method, name it `test_{method_name_with_underscores}`.
58+
E.g. the test for `_internal_function` is named `test__internal_function`.
59+
E.g. the test for `MyClass.my_method` is named `TestMyClass.test_my_method`.
60+
61+
When testing a special case of a function or method append a `__{special_case}` to the test name.
62+
E.g. the test for the function `compute_mean(arr: list[float])` for the empty array case
63+
should be named `test_compute_mean__empty_array`.

.github/pull_request_template.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
## What has changed and why?
2+
3+
(Delete this: Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.)
4+
5+
## How has it been tested?
6+
7+
(Delete this: Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.)
8+
9+
## Did you update [CHANGELOG.md](../CHANGELOG.md)?
10+
11+
- [ ] Yes
12+
- [ ] Not needed (internal change)

.github/workflows/end2end_test.yml

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
name: End2End Test
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
workflow_dispatch:
9+
10+
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
env:
16+
NODE_OPTIONS: --max-old-space-size=4096
17+
DATASET_PATH: $(pwd)/datasets
18+
E2E_BASE_URL: http://localhost:8001
19+
LIGHTLY_STUDIO_LICENSE_KEY: ${{ secrets.MUNDIG_LICENSE_KEY }}
20+
21+
jobs:
22+
end-to-end-test:
23+
name: End2End Test
24+
runs-on: ubuntu-latest
25+
steps:
26+
- name: Checkout Code
27+
uses: actions/checkout@v4
28+
with:
29+
submodules: recursive
30+
31+
# Authenticate to download lightly-edge-sdk.
32+
- name: Authenticate with GCP
33+
uses: 'google-github-actions/auth@v2'
34+
with:
35+
project_id: boris-250909
36+
credentials_json: ${{ secrets.GCP_LIGHTLY_STUDIO_CI_READONLY }}
37+
38+
### Caching rules for the workflow ###
39+
- name: Cache UI app build
40+
id: cache-ui-build
41+
uses: actions/cache@v4
42+
with:
43+
path: |
44+
lightly_studio_view/build
45+
lightly_studio/src/lightly_studio/dist_lightly_studio_view_app
46+
key: ui-build-${{ hashFiles('lightly_studio_view/src/**', 'lightly_studio_view/public/**', 'lightly_studio_view/package.json', 'lightly_studio_view/package-lock.json') }}
47+
48+
- name: Cache example dataset
49+
id: cache-example-dataset
50+
uses: actions/cache@v4
51+
with:
52+
path: lightly_studio/datasets/coco-128
53+
key: coco-example-dataset
54+
55+
- name: Cache lightly_studio app build
56+
id: cache-python-build
57+
uses: actions/cache@v4
58+
with:
59+
path: lightly_studio/dist
60+
key: python-build-${{ hashFiles('lightly_studio/src/**', 'lightly_studio/pyproject.toml', 'lightly_studio_view/src/**', 'lightly_studio_view/public/**', 'lightly_studio_view/package.json', 'lightly_studio_view/package-lock.json') }}
61+
62+
- name: Cache e2e-tests
63+
id: cache-e2e-tests
64+
uses: actions/cache@v4
65+
with:
66+
path: lightly_studio_view/playwright-report
67+
key: python-build-${{ hashFiles('lightly_studio/e2e-tests/index_dataset_for_end2end_ui_tests.py', 'lightly_studio/src/**', 'lightly_studio/pyproject.toml', 'lightly_studio_view/e2e/**', 'lightly_studio_view/src/**', 'lightly_studio_view/public/**', 'lightly_studio_view/package.json', 'lightly_studio_view/package-lock.json') }}
68+
69+
### Setup steps for the workflow ###
70+
- name: Set Up Python
71+
if: steps.cache-python-build.outputs.cache-hit != 'true' || steps.cache-e2e-tests.outputs.cache-hit != 'true'
72+
uses: actions/setup-python@v5
73+
with:
74+
python-version: "3.8"
75+
76+
- name: Set Up uv
77+
if: steps.cache-python-build.outputs.cache-hit != 'true' || steps.cache-e2e-tests.outputs.cache-hit != 'true'
78+
uses: astral-sh/setup-uv@v6
79+
with:
80+
version: "0.8.17"
81+
enable-cache: true
82+
83+
- name: Set Up Node.js
84+
uses: actions/setup-node@v4
85+
with:
86+
node-version: '22.11.0'
87+
cache: 'npm'
88+
cache-dependency-path: lightly_studio_view/package-lock.json
89+
90+
- name: Install dependencies
91+
if: steps.cache-e2e-tests.outputs.cache-hit != 'true' || steps.cache-python-build.outputs.cache-hit != 'true'
92+
working-directory: lightly_studio_view
93+
run: npm ci
94+
95+
# Cache Playwright browsers to avoid re-downloading each run
96+
- name: Cache Playwright browsers
97+
id: cache-playwright-browsers
98+
uses: actions/cache@v4
99+
with:
100+
path: ~/.cache/ms-playwright
101+
key: playwright-${{ runner.os }}-${{ hashFiles('lightly_studio_view/package-lock.json') }}
102+
103+
# Always ensure system packages for browsers are present on Ubuntu
104+
- name: Install Playwright system dependencies
105+
if: steps.cache-e2e-tests.outputs.cache-hit != 'true'
106+
working-directory: lightly_studio_view
107+
run: npx playwright install-deps chromium
108+
109+
# Only download browser binaries when cache misses; otherwise reuse cache
110+
- name: Install Playwright browsers
111+
if: steps.cache-e2e-tests.outputs.cache-hit != 'true' && steps.cache-playwright-browsers.outputs.cache-hit != 'true'
112+
working-directory: lightly_studio_view
113+
run: npx playwright install chromium
114+
115+
- name: Download example dataset
116+
if: steps.cache-example-dataset.outputs.cache-hit != 'true'
117+
run: |
118+
mkdir -p lightly_studio/datasets/coco-128
119+
git clone --depth=1 https://github.com/lightly-ai/dataset_examples_studio.git tmp_dataset_repo
120+
cp -r tmp_dataset_repo/coco_subset_128_images/* lightly_studio/datasets/coco-128/
121+
rm -rf tmp_dataset_repo
122+
123+
- name: Install lightly_studio python dependencies
124+
if: steps.cache-python-build.outputs.cache-hit != 'true'
125+
working-directory: lightly_studio
126+
run: make install-optional-deps
127+
128+
- name: Export schema from backend
129+
if: steps.cache-python-build.outputs.cache-hit != 'true'
130+
working-directory: lightly_studio
131+
run: make export-schema
132+
133+
### Buildging and steps for the workflow ###
134+
- name: Build the ui application
135+
if: steps.cache-ui-build.outputs.cache-hit != 'true' || steps.cache-python-build.outputs.cache-hit != 'true'
136+
working-directory: lightly_studio_view
137+
run: |
138+
rm -rf build
139+
npm run build
140+
141+
- name: Copy the built ui app to lightly_studio source folder
142+
if: steps.cache-ui-build.outputs.cache-hit != 'true' || steps.cache-python-build.outputs.cache-hit != 'true'
143+
run: |
144+
rm -rf lightly_studio/src/lightly_studio/dist_lightly_studio_view_app
145+
cp -r lightly_studio_view/build/ lightly_studio/src/lightly_studio/dist_lightly_studio_view_app
146+
147+
- name: Index dataset with using lightly_studio pypi package
148+
if: steps.cache-e2e-tests.outputs.cache-hit != 'true'
149+
working-directory: lightly_studio
150+
# TODO(Michal, 10/2025): Starting up the server redownloads the embedding model. Consider caching it.
151+
run: |
152+
uv run e2e-tests/index_dataset_for_end2end_ui_tests.py > server.log 2>&1 &
153+
echo "SERVER_PID=$!" >> $GITHUB_ENV
154+
id: server
155+
156+
- name: Wait for the server to start
157+
if: steps.cache-e2e-tests.outputs.cache-hit != 'true'
158+
timeout-minutes: 5
159+
run: |
160+
echo "Waiting for the server to become available..."
161+
timeout=360
162+
elapsed=0
163+
interval=5
164+
165+
while [ $elapsed -lt $timeout ]; do
166+
if curl -s -f ${E2E_BASE_URL}/healthz > /dev/null 2>&1; then
167+
echo "✅ Server is up and running after ${elapsed} seconds!"
168+
break
169+
fi
170+
echo "⏳ Server not ready yet, waiting... (${elapsed}/${timeout} seconds)"
171+
sleep $interval
172+
elapsed=$((elapsed + interval))
173+
done
174+
175+
if [ $elapsed -ge $timeout ]; then
176+
echo "❌ Timed out waiting for server to become available"
177+
exit 1
178+
fi
179+
180+
### Running end-to-end tests ###
181+
- name: Run end-to-end tests for indexed dataset
182+
if: steps.cache-e2e-tests.outputs.cache-hit != 'true'
183+
working-directory: lightly_studio_view
184+
run: npx playwright test --reporter=html --trace=on
185+
timeout-minutes: 10
186+
187+
### Cleanup steps for the workflow ###
188+
- name: Show server logs after failure
189+
if: failure() && steps.cache-e2e-tests.outputs.cache-hit != 'true'
190+
working-directory: lightly_studio
191+
run: |
192+
echo "Server logs:"
193+
cat server.log
194+
195+
- name: Upload Playwright report after failure
196+
uses: actions/upload-artifact@v4
197+
if: failure()
198+
with:
199+
name: Upload Playwright Report
200+
path: lightly_studio_view/playwright-report
201+
retention-days: 5
202+
203+
- name: Stop lightly_studio application running in background
204+
if: always() && steps.cache-e2e-tests.outputs.cache-hit != 'true'
205+
run: |
206+
kill ${{ env.SERVER_PID }} || true

0 commit comments

Comments
 (0)