Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/code-checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Code Checks

on:
pull_request:

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
format:
name: Format check

runs-on: ubuntu-latest

strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v3

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Ruff format check
uses: astral-sh/ruff-action@v3
with:
args: "format --check --diff"
182 changes: 100 additions & 82 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Python SDK Tests

on:
pull_request:

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

Expand All @@ -12,93 +12,111 @@ jobs:
pull-requests: write

runs-on: ubuntu-latest

strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v3

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
working-directory: ./
run: |
python -m pip install --upgrade pip
pip install pytest pytest-cov
pip install -e .
pip install -r dev-requirements.txt

- name: Run tests
working-directory: ./
run: |
pytest tests/ --cov=basalt --cov-report=term --cov-report=xml
echo "PYTHON_VERSION=${{ matrix.python-version }}" >> $GITHUB_OUTPUT
echo "COVERAGE_PCT=$(python -c "import xml.etree.ElementTree as ET; tree = ET.parse('coverage.xml'); root = tree.getroot(); print(f'{float(root.attrib[\"line-rate\"]) * 100:.2f}')")" >> $GITHUB_OUTPUT
echo "TEST_COUNT=$(python -c "import xml.etree.ElementTree as ET; tree = ET.parse('coverage.xml'); root = tree.getroot(); print(root.find('.//metrics').attrib['tests'])")" >> $GITHUB_OUTPUT
id: test_results

- name: Create result file
run: |
mkdir -p test-results
echo "${{ steps.test_results.outputs.COVERAGE_PCT }}" > test-results/coverage.txt
echo "${{ steps.test_results.outputs.TEST_COUNT }}" > test-results/test-count.txt

- name: Upload test results
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.python-version }}
path: test-results/
- uses: actions/checkout@v3

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
working-directory: ./
run: |
python -m pip install --upgrade pip
pip install pytest pytest-cov
pip install -e .
pip install -r dev-requirements.txt

- name: Run tests
working-directory: ./
run: |
pytest tests/ \
--cov=basalt --cov-report=term --cov-report=xml \
--junitxml=pytest-report.xml

echo "PYTHON_VERSION=${{ matrix.python-version }}" >> "$GITHUB_OUTPUT"

echo "COVERAGE_PCT=$(python - <<'PY'
import xml.etree.ElementTree as ET
rate = float(ET.parse('coverage.xml').getroot().attrib['line-rate']) * 100
print(f'{rate:.2f}')
PY
)" >> "$GITHUB_OUTPUT"

echo "TEST_COUNT=$(python - <<'PY'
import xml.etree.ElementTree as ET
root = ET.parse('pytest-report.xml').getroot()
if root.tag == 'testsuite':
print(root.attrib['tests'])
else:
print(sum(int(s.attrib['tests']) for s in root.findall('testsuite')))
PY
)" >> "$GITHUB_OUTPUT"
id: test_results

- name: Create result file
run: |
mkdir -p test-results
echo "${{ steps.test_results.outputs.COVERAGE_PCT }}" > test-results/coverage.txt
echo "${{ steps.test_results.outputs.TEST_COUNT }}" > test-results/test-count.txt

- name: Upload test results
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.python-version }}
path: test-results/

comment:
needs: test
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'

steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Prepare comment
id: prepare_comment
run: |
echo "COMMENT_BODY<<EOF" >> $GITHUB_ENV
echo "## Python SDK Test Results" >> $GITHUB_ENV
echo "" >> $GITHUB_ENV
echo "| Python Version | Status | Coverage | Tests Run |" >> $GITHUB_ENV
echo "| -------------- | ------ | -------- | --------- |" >> $GITHUB_ENV
for version in 3.8 3.9 3.10 3.11 3.12; do
version_path="test-results-$version"
if [ -d "$version_path" ] && [ -f "$version_path/coverage.txt" ]; then
coverage=$(cat "$version_path/coverage.txt")
test_count=$(cat "$version_path/test-count.txt")
echo "| Python $version | ✅ Passed | $coverage% | $test_count |" >> $GITHUB_ENV
else
echo "| Python $version | ❌ Failed or not run | - | - |" >> $GITHUB_ENV
fi
done
echo "" >> $GITHUB_ENV
echo "*Last updated: $(date -u '+%Y-%m-%d %H:%M:%S UTC')*" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Find Comment
uses: peter-evans/find-comment@v3
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-includes: Python SDK Test Results

- name: Create or update comment
uses: peter-evans/create-or-update-comment@v4
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body: ${{ env.COMMENT_BODY }}
edit-mode: replace
- name: Download all artifacts
uses: actions/download-artifact@v4

- name: Prepare comment
id: prepare_comment
run: |
echo "COMMENT_BODY<<EOF" >> $GITHUB_ENV
echo "## Python SDK Test Results" >> $GITHUB_ENV
echo "" >> $GITHUB_ENV
echo "| Python Version | Status | Coverage | Tests Run |" >> $GITHUB_ENV
echo "| -------------- | ------ | -------- | --------- |" >> $GITHUB_ENV

for version in 3.8 3.9 3.10 3.11 3.12 3.13; do
version_path="test-results-$version"
if [ -d "$version_path" ] && [ -f "$version_path/coverage.txt" ]; then
coverage=$(cat "$version_path/coverage.txt")
test_count=$(cat "$version_path/test-count.txt")
echo "| Python $version | ✅ Passed | $coverage% | $test_count |" >> $GITHUB_ENV
else
echo "| Python $version | ❌ Failed or not run | - | - |" >> $GITHUB_ENV
fi
done

echo "" >> $GITHUB_ENV
echo "*Last updated: $(date -u '+%Y-%m-%d %H:%M:%S UTC')*" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV

- name: Find Comment
uses: peter-evans/find-comment@v3
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: "github-actions[bot]"
body-includes: Python SDK Test Results

- name: Create or update comment
uses: peter-evans/create-or-update-comment@v4
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body: ${{ env.COMMENT_BODY }}
edit-mode: replace
7 changes: 4 additions & 3 deletions basalt/basalt_facade.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@

global_fallback_cache = MemoryCache()


class BasaltFacade(IBasaltSDK):
"""
The Basalt client.
"""

def __init__(self, api_key: str, log_level: str = 'all'):
def __init__(self, api_key: str, log_level: str = "all"):
"""
Initializes the Basalt client with the given API key and log level.

Expand All @@ -26,14 +27,14 @@ def __init__(self, api_key: str, log_level: str = 'all'):
cache = MemoryCache()
logger = Logger(log_level=log_level)
networker = Networker(logger=logger)

api = Api(
networker=networker,
root_url=config["api_url"],
api_key=api_key,
sdk_version=config["sdk_version"],
sdk_type=config["sdk_type"],
logger=logger
logger=logger,
)

prompt = PromptSDK(api, cache, global_fallback_cache, logger)
Expand Down
3 changes: 2 additions & 1 deletion basalt/basaltsdk.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .utils.protocols import IPromptSDK, IBasaltSDK, IMonitorSDK


class BasaltSDK(IBasaltSDK):
"""
The BasaltSDK class implements the IBasaltSDK interface.
Expand All @@ -9,7 +10,7 @@ class BasaltSDK(IBasaltSDK):
def __init__(self, prompt_sdk: IPromptSDK, monitor_sdk: IMonitorSDK):
self._prompt = prompt_sdk
self._monitor = monitor_sdk

@property
def prompt(self) -> IPromptSDK:
"""Read-only access to the PromptSDK instance"""
Expand Down
8 changes: 5 additions & 3 deletions basalt/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
from ._version import __version__

config = {
'api_url': 'http://localhost:3001' if build == 'development' else 'https://api.getbasalt.ai',
'sdk_version': __version__,
'sdk_type': 'python',
"api_url": "http://localhost:3001"
if build == "development"
else "https://api.getbasalt.ai",
"sdk_version": __version__,
"sdk_type": "python",
}
16 changes: 9 additions & 7 deletions basalt/endpoints/describe_prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from ..utils.dtos import DescribePromptDTO, DescribePromptResponse


@dataclass
class DescribePromptEndpointResponse:
warning: Optional[str]
Expand All @@ -24,10 +25,12 @@ def from_dict(cls, data: Dict[str, Any]) -> "DescribePromptEndpointResponse":
prompt=DescribePromptResponse.from_dict(data["prompt"]),
)


class DescribePromptEndpoint:
"""
Endpoint class for fetching a prompt.
"""

@staticmethod
def prepare_request(dto: DescribePromptDTO) -> Dict[str, Any]:
"""
Expand All @@ -37,27 +40,26 @@ def prepare_request(dto: DescribePromptDTO) -> Dict[str, Any]:
dto (DescribePromptDTO): The data transfer object containing the request parameters.

Returns:
The path, method, and query parameters for describing a prompt on the API.
The path, method, and query parameters for describing a prompt on the API.
"""
return {
"path": f"/prompts/{dto.slug}/describe",
"method": "GET",
"query": {
"version": dto.version,
"tag": dto.tag
}
"query": {"version": dto.version, "tag": dto.tag},
}

@staticmethod
def decode_response(response: dict) -> Tuple[Optional[Exception], Optional[DescribePromptEndpointResponse]]:
def decode_response(
response: dict,
) -> Tuple[Optional[Exception], Optional[DescribePromptEndpointResponse]]:
"""
Decode the response returned from the API

Args:
response (dict): The JSON response to encode into a DescribePromptEndpointResponse

Returns:
A tuple containing an optional exception and an optional DescribePromptEndpointResponse.
A tuple containing an optional exception and an optional DescribePromptEndpointResponse.
"""
try:
return None, DescribePromptEndpointResponse.from_dict(response)
Expand Down
Loading