Skip to content

Commit 9c2b57c

Browse files
committed
feat(catalog): add generated Python client for Model Catalog API
Signed-off-by: Alessio Pragliola <[email protected]>
1 parent 590a886 commit 9c2b57c

Some content is hidden

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

54 files changed

+11936
-0
lines changed

.gitattributes

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,46 @@
33

44
# Do not edit below this line. Edits will be overwritten by gen_gitattributes.sh
55

6+
catalog/clients/python/src/catalog_openapi/__init__.py linguist-generated=true
7+
catalog/clients/python/src/catalog_openapi/api/model_catalog_service_api.py linguist-generated=true
8+
catalog/clients/python/src/catalog_openapi/api_client.py linguist-generated=true
9+
catalog/clients/python/src/catalog_openapi/configuration.py linguist-generated=true
10+
catalog/clients/python/src/catalog_openapi/exceptions.py linguist-generated=true
11+
catalog/clients/python/src/catalog_openapi/models/__init__.py linguist-generated=true
12+
catalog/clients/python/src/catalog_openapi/models/artifact_type_query_param.py linguist-generated=true
13+
catalog/clients/python/src/catalog_openapi/models/base_model.py linguist-generated=true
14+
catalog/clients/python/src/catalog_openapi/models/base_resource.py linguist-generated=true
15+
catalog/clients/python/src/catalog_openapi/models/base_resource_dates.py linguist-generated=true
16+
catalog/clients/python/src/catalog_openapi/models/base_resource_list.py linguist-generated=true
17+
catalog/clients/python/src/catalog_openapi/models/catalog_artifact.py linguist-generated=true
18+
catalog/clients/python/src/catalog_openapi/models/catalog_artifact_list.py linguist-generated=true
19+
catalog/clients/python/src/catalog_openapi/models/catalog_label.py linguist-generated=true
20+
catalog/clients/python/src/catalog_openapi/models/catalog_label_list.py linguist-generated=true
21+
catalog/clients/python/src/catalog_openapi/models/catalog_metrics_artifact.py linguist-generated=true
22+
catalog/clients/python/src/catalog_openapi/models/catalog_model.py linguist-generated=true
23+
catalog/clients/python/src/catalog_openapi/models/catalog_model_artifact.py linguist-generated=true
24+
catalog/clients/python/src/catalog_openapi/models/catalog_model_list.py linguist-generated=true
25+
catalog/clients/python/src/catalog_openapi/models/catalog_source.py linguist-generated=true
26+
catalog/clients/python/src/catalog_openapi/models/catalog_source_list.py linguist-generated=true
27+
catalog/clients/python/src/catalog_openapi/models/catalog_source_preview_response.py linguist-generated=true
28+
catalog/clients/python/src/catalog_openapi/models/catalog_source_preview_response_all_of_summary.py linguist-generated=true
29+
catalog/clients/python/src/catalog_openapi/models/catalog_source_status.py linguist-generated=true
30+
catalog/clients/python/src/catalog_openapi/models/error.py linguist-generated=true
31+
catalog/clients/python/src/catalog_openapi/models/field_filter.py linguist-generated=true
32+
catalog/clients/python/src/catalog_openapi/models/filter_option.py linguist-generated=true
33+
catalog/clients/python/src/catalog_openapi/models/filter_option_range.py linguist-generated=true
34+
catalog/clients/python/src/catalog_openapi/models/filter_options_list.py linguist-generated=true
35+
catalog/clients/python/src/catalog_openapi/models/metadata_bool_value.py linguist-generated=true
36+
catalog/clients/python/src/catalog_openapi/models/metadata_double_value.py linguist-generated=true
37+
catalog/clients/python/src/catalog_openapi/models/metadata_int_value.py linguist-generated=true
38+
catalog/clients/python/src/catalog_openapi/models/metadata_proto_value.py linguist-generated=true
39+
catalog/clients/python/src/catalog_openapi/models/metadata_string_value.py linguist-generated=true
40+
catalog/clients/python/src/catalog_openapi/models/metadata_struct_value.py linguist-generated=true
41+
catalog/clients/python/src/catalog_openapi/models/metadata_value.py linguist-generated=true
42+
catalog/clients/python/src/catalog_openapi/models/model_preview_result.py linguist-generated=true
43+
catalog/clients/python/src/catalog_openapi/models/order_by_field.py linguist-generated=true
44+
catalog/clients/python/src/catalog_openapi/models/sort_order.py linguist-generated=true
45+
catalog/clients/python/src/catalog_openapi/rest.py linguist-generated=true
646
catalog/internal/server/openapi/api.go linguist-generated=true
747
catalog/internal/server/openapi/api_model_catalog_service.go linguist-generated=true
848
catalog/internal/server/openapi/error.go linguist-generated=true

catalog/clients/python/.gitignore

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Python
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
*.egg-info/
6+
7+
# Type checking
8+
.mypy_cache/
9+
10+
# Testing
11+
.pytest_cache/
12+
/.coverage*
13+
htmlcov/
14+
.hypothesis/
15+
.schemathesis/
16+
17+
# Build
18+
/dist/
19+
/build/
20+
21+
# Virtual environments
22+
venv/
23+
.venv/
24+
env/
25+
26+
# Nox
27+
/.nox/
28+
29+
# Ruff
30+
.ruff_cache/
31+
32+
# Documentation
33+
/docs/_build/
34+
35+
# IDE
36+
.vscode/
37+
.idea/
38+
*.swp
39+
*.swo
40+
*~
41+
42+
# Poetry
43+
.python-version
44+
45+
# Logs and temp files
46+
*.log
47+
*.tmp
48+
49+
# Kubernetes/Deployment
50+
.port-forward.pid
51+
52+
# Screenshots from browser testing
53+
*.png
54+
*.jpeg

catalog/clients/python/Makefile

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# Makefile for Model Catalog Python Client
2+
3+
all: install tidy
4+
5+
.PHONY: help
6+
help:
7+
@echo "Model Catalog Python Client Targets:"
8+
@echo ""
9+
@echo " Setup & Build:"
10+
@echo " install - Generate OpenAPI client and install dependencies"
11+
@echo " generate - Regenerate catalog API client from OpenAPI spec"
12+
@echo " clean - Remove generated code and caches"
13+
@echo " build - Build the package"
14+
@echo ""
15+
@echo " Testing:"
16+
@echo " test-e2e - Run E2E tests (requires running catalog)"
17+
@echo " test-fuzz - Run fuzz tests (requires running catalog)"
18+
@echo ""
19+
@echo " Code Quality:"
20+
@echo " lint - Run linters (ruff + mypy)"
21+
@echo " tidy - Auto-fix code style issues"
22+
@echo ""
23+
@echo " Nox Sessions (multi-Python testing):"
24+
@echo " nox - Run default nox sessions"
25+
@echo " nox-lint - Run lint on all Python versions"
26+
@echo " nox-e2e - Run E2E tests on all Python versions"
27+
@echo ""
28+
@echo " Deployment (K8s with Kustomize):"
29+
@echo " deploy - Full local deployment (Kind + build + deploy)"
30+
@echo " deploy-kind - Create Kind cluster"
31+
@echo " deploy-build - Build Docker image"
32+
@echo " deploy-load - Load image into Kind cluster"
33+
@echo " deploy-k8s - Deploy to existing cluster (no Kind, no build)"
34+
@echo " deploy-apply - Apply kustomize manifests"
35+
@echo " deploy-forward - Start port-forward"
36+
@echo " deploy-restart - Rebuild and restart catalog (quick dev cycle)"
37+
@echo " deploy-cleanup - Remove deployment and Kind cluster"
38+
39+
# Configuration (can be overridden: make deploy CATALOG_PORT=9090)
40+
export CATALOG_NAMESPACE ?= model-catalog
41+
export CATALOG_IMAGE ?= model-registry:catalog-test
42+
export CLUSTER_NAME ?= catalog-e2e
43+
export CATALOG_PORT ?= 8081
44+
45+
# Kustomize overlay for E2E testing
46+
KUSTOMIZE_E2E := ../../../manifests/kustomize/options/catalog/overlays/e2e
47+
48+
.PHONY: install
49+
install: generate
50+
poetry install
51+
52+
.PHONY: generate
53+
generate:
54+
@echo "Generating Catalog API client from OpenAPI spec..."
55+
@mkdir -p src/catalog_openapi
56+
../../../bin/openapi-generator-cli generate \
57+
-i ../../../api/openapi/catalog.yaml \
58+
-g python \
59+
-o src/ \
60+
--package-name catalog_openapi \
61+
--additional-properties=library=urllib3,generateSourceCodeOnly=true,useOneOfDiscriminatorLookup=true
62+
@# Remove generated test and docs
63+
@rm -rf src/catalog_openapi/test src/catalog_openapi/docs
64+
@rm -f src/catalog_openapi_README.md
65+
@if [ -d patches ] && [ -n "$$(ls -A patches/*.patch 2>/dev/null)" ]; then \
66+
echo "Applying patches..."; \
67+
git apply patches/*.patch; \
68+
fi
69+
@echo "[OK] Generated catalog_openapi package"
70+
71+
.PHONY: clean
72+
clean:
73+
@echo "Cleaning generated code and caches..."
74+
rm -rf src/catalog_openapi/
75+
rm -rf .pytest_cache/
76+
rm -rf .ruff_cache/
77+
rm -rf .mypy_cache/
78+
rm -rf .nox/
79+
rm -rf .coverage
80+
rm -rf .coverage.*
81+
rm -rf htmlcov/
82+
rm -rf dist/
83+
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
84+
find . -type f -name "*.pyc" -delete
85+
@echo "[OK] Cleaned"
86+
87+
.PHONY: test-e2e
88+
test-e2e:
89+
CATALOG_URL=$${CATALOG_URL:-http://localhost:$(CATALOG_PORT)} poetry run pytest --e2e -v -rA
90+
91+
.PHONY: test-fuzz
92+
test-fuzz:
93+
CATALOG_URL=$${CATALOG_URL:-http://localhost:$(CATALOG_PORT)} poetry run pytest --fuzz -v
94+
95+
.PHONY: lint
96+
lint:
97+
poetry run ruff check .
98+
poetry run mypy .
99+
100+
.PHONY: tidy
101+
tidy:
102+
@echo "Fixing code style issues..."
103+
-poetry run ruff check --fix-only . src/catalog_openapi 2>/dev/null
104+
-poetry run ruff format src tests 2>/dev/null
105+
106+
.PHONY: build
107+
build: install tidy
108+
poetry build
109+
110+
.PHONY: update
111+
update:
112+
poetry lock
113+
114+
# Nox sessions for multi-Python version testing
115+
.PHONY: nox
116+
nox:
117+
poetry run nox
118+
119+
.PHONY: nox-lint
120+
nox-lint:
121+
poetry run nox -s lint
122+
123+
.PHONY: nox-e2e
124+
nox-e2e:
125+
poetry run nox -s e2e
126+
127+
# =============================================================================
128+
# Deployment Targets
129+
# =============================================================================
130+
131+
# Full local deployment: Kind cluster + build + deploy everything
132+
.PHONY: deploy
133+
deploy: deploy-kind deploy-build deploy-load deploy-k8s deploy-forward
134+
@echo ""
135+
@echo "========================================"
136+
@echo "[OK] Deployment complete!"
137+
@echo "========================================"
138+
@echo ""
139+
@echo "Catalog URL: http://localhost:$(CATALOG_PORT)"
140+
@echo ""
141+
@echo "Run tests: make test-e2e"
142+
@echo "View logs: kubectl logs -f deployment/model-catalog-server -n $(CATALOG_NAMESPACE)"
143+
@echo "Cleanup: make deploy-cleanup"
144+
145+
# Deploy to existing cluster (no Kind, no build)
146+
.PHONY: deploy-k8s
147+
deploy-k8s: deploy-namespace deploy-apply
148+
149+
# Create Kind cluster
150+
.PHONY: deploy-kind
151+
deploy-kind:
152+
@echo "Setting up Kind cluster: $(CLUSTER_NAME)"
153+
@if kind get clusters 2>/dev/null | grep -q "$(CLUSTER_NAME)"; then \
154+
echo "Cluster $(CLUSTER_NAME) already exists, using it"; \
155+
kubectl config use-context "kind-$(CLUSTER_NAME)"; \
156+
else \
157+
kind create cluster -n "$(CLUSTER_NAME)"; \
158+
fi
159+
160+
# Build Docker image
161+
.PHONY: deploy-build
162+
deploy-build:
163+
@echo "Building Docker image: $(CATALOG_IMAGE)"
164+
cd ../../.. && docker build --progress=plain -t "$(CATALOG_IMAGE)" -f Dockerfile .
165+
@echo "[OK] Build complete"
166+
167+
# Load image into Kind cluster
168+
.PHONY: deploy-load
169+
deploy-load:
170+
@echo "Loading image into Kind cluster..."
171+
kind load docker-image -n "$(CLUSTER_NAME)" "$(CATALOG_IMAGE)" 2>&1 | tail -5
172+
@# Adjust image name for podman if needed
173+
@if docker --version 2>&1 | grep -q "podman"; then \
174+
echo "Using podman, image will be referenced as localhost/$(CATALOG_IMAGE)"; \
175+
fi
176+
177+
# Create namespace
178+
.PHONY: deploy-namespace
179+
deploy-namespace:
180+
@echo "Creating namespace: $(CATALOG_NAMESPACE)"
181+
kubectl create namespace "$(CATALOG_NAMESPACE)" --dry-run=client -o yaml | kubectl apply -f -
182+
183+
# Apply kustomize manifests (includes postgres, secrets, configmaps, catalog)
184+
.PHONY: deploy-apply
185+
deploy-apply: deploy-namespace
186+
@echo "Applying kustomize manifests..."
187+
@# Set the image dynamically to support both Docker and Podman
188+
cd "$(KUSTOMIZE_E2E)" && kustomize edit set image "ghcr.io/kubeflow/model-registry/server=$(CATALOG_IMAGE)"
189+
kubectl apply -k "$(KUSTOMIZE_E2E)"
190+
@echo "Waiting for PostgreSQL to be ready..."
191+
kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=postgres -n "$(CATALOG_NAMESPACE)" --timeout=120s
192+
@echo "[OK] PostgreSQL is ready"
193+
@echo "Waiting for Catalog to be ready..."
194+
kubectl wait --for=condition=available deployment/model-catalog-server -n "$(CATALOG_NAMESPACE)" --timeout=120s
195+
@echo "[OK] Catalog service is ready"
196+
197+
# Start port-forward
198+
.PHONY: deploy-forward
199+
deploy-forward:
200+
@echo "Starting port-forward on port $(CATALOG_PORT)..."
201+
@# Stop any existing port-forward first to avoid stale PIDs
202+
@if [ -f .port-forward.pid ]; then \
203+
kill $$(cat .port-forward.pid) 2>/dev/null || true; \
204+
rm -f .port-forward.pid; \
205+
fi
206+
@kubectl port-forward -n "$(CATALOG_NAMESPACE)" svc/model-catalog "$(CATALOG_PORT)":8080 > /dev/null 2>&1 & echo $$! > .port-forward.pid
207+
@sleep 3
208+
@if curl -s "http://localhost:$(CATALOG_PORT)/api/model_catalog/v1alpha1/sources" > /dev/null 2>&1; then \
209+
echo "[OK] Catalog accessible at http://localhost:$(CATALOG_PORT)"; \
210+
else \
211+
echo "[WARN] Port-forward may not be ready. Try: kubectl port-forward -n $(CATALOG_NAMESPACE) svc/model-catalog $(CATALOG_PORT):8080"; \
212+
fi
213+
214+
# Stop port-forward
215+
.PHONY: deploy-forward-stop
216+
deploy-forward-stop:
217+
@echo "Stopping port-forward..."
218+
@if [ -f .port-forward.pid ]; then \
219+
kill $$(cat .port-forward.pid) 2>/dev/null || true; \
220+
rm -f .port-forward.pid; \
221+
fi
222+
223+
# Cleanup everything
224+
.PHONY: deploy-cleanup
225+
deploy-cleanup: deploy-forward-stop
226+
@echo "Cleaning up deployment..."
227+
@if kubectl get namespace "$(CATALOG_NAMESPACE)" &>/dev/null; then \
228+
kubectl delete namespace "$(CATALOG_NAMESPACE)" --timeout=60s || true; \
229+
fi
230+
@if kind get clusters 2>/dev/null | grep -q "$(CLUSTER_NAME)"; then \
231+
echo "Deleting Kind cluster: $(CLUSTER_NAME)"; \
232+
kind delete cluster -n "$(CLUSTER_NAME)"; \
233+
fi
234+
@echo "[OK] Cleanup complete"
235+
236+
# Shortcut: redeploy catalog only (after code changes)
237+
.PHONY: deploy-restart
238+
deploy-restart: deploy-build deploy-load
239+
kubectl rollout restart deployment/model-catalog-server -n "$(CATALOG_NAMESPACE)"
240+
kubectl rollout status deployment/model-catalog-server -n "$(CATALOG_NAMESPACE)"
241+
@echo "[OK] Catalog restarted"

0 commit comments

Comments
 (0)