Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Dependencies #8

Merged
merged 6 commits into from
Dec 8, 2023
Merged
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
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
- published

env:
PYTHON_VERSION: '3.10'
PYTHON_VERSION: '3.11'

concurrency:
group: ${{ github.head_ref || github.run_id }}
Expand All @@ -18,9 +18,9 @@ jobs:
precommit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install pre-commit
Expand All @@ -34,10 +34,10 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Python ${{ env.PYTHON_VERSION }}
# deadsnakes python required due to https://github.com/JonathonReinhart/staticx/issues/188
uses: deadsnakes/action@v2.1.1
uses: deadsnakes/action@v3.1.0
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install dependencies
Expand All @@ -57,10 +57,10 @@ jobs:
needs: [precommit, build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Python ${{ env.PYTHON_VERSION }}
# deadsnakes python required due to https://github.com/JonathonReinhart/staticx/issues/188
uses: deadsnakes/action@v2.1.1
uses: deadsnakes/action@v3.1.0
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install dependencies
Expand Down
12 changes: 6 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: check-docstring-first
- id: debug-statements
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace
- repo: https://github.com/asottile/pyupgrade
rev: v3.3.1
rev: v3.15.0
hooks:
- id: pyupgrade
language: python
args: [--py310-plus]
args: [--py311-plus]
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
- repo: https://github.com/ambv/black
rev: 23.1.0
rev: 23.11.0
hooks:
- id: black
language: python
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
rev: 6.1.0
hooks:
- id: flake8
language: python
Expand All @@ -35,7 +35,7 @@ repos:
- mccabe
- yesqa
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v1.1.1'
rev: 'v1.7.1'
hooks:
- id: mypy
additional_dependencies:
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.10
FROM python:3.11

RUN mkdir -p /opt/src/dist

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The application contains:
- A `fastapi` web server that implements the SageMaker endpoints
- and `pydantic` models that interface between S3, and run the original inference jobs.

The application is compiled on Python 3.10 using `pyinstaller`, and then distributed as a statically linked binary using `staticx`.
The application is compiled on Python 3.11 using `pyinstaller`, and then distributed as a statically linked binary using `staticx`.
It is able to adapt any container, including ones based on `scratch` or `alpine` images.

## Usage
Expand Down
4 changes: 2 additions & 2 deletions dist/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ sagemaker-shim-static-${TEST_VERSION}: sagemaker-shim-${TEST_VERSION}
staticx "sagemaker-shim-${TEST_VERSION}" "sagemaker-shim-static-${TEST_VERSION}"

crane-src.tar.gz:
wget https://github.com/google/go-containerregistry/releases/download/v0.9.0/go-containerregistry_Linux_x86_64.tar.gz -O crane-src.tar.gz && \
echo "1d2cf3fac0830dd8e5fb6e2829fdfc304a3d4a0f48f7e1df9ebb7e2921f28803 crane-src.tar.gz" | shasum -c - || exit 1
curl -L https://github.com/google/go-containerregistry/releases/download/v0.17.0/go-containerregistry_Linux_x86_64.tar.gz -o crane-src.tar.gz && \
echo "1b4d3ee1e214776bd74b88741ccf1b070e8ed5660056f05af632a1a399fe21c6 crane-src.tar.gz" | shasum -c - || exit 1

crane: crane-src.tar.gz
tar -xzvf crane-src.tar.gz crane && \
Expand Down
2,176 changes: 1,131 additions & 1,045 deletions poetry.lock

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ sagemaker-shim = "sagemaker_shim.cli:cli"

[tool.poetry.dependencies]
# Only support one version of python at a time
python = "^3.10,<3.11"
python = "^3.11,<3.12"
fastapi = "!=0.89.0"
uvicorn = {extras = ["standard"], version = "*"}
click = "*"
Expand All @@ -29,7 +29,9 @@ httpx = "*"
pytest-randomly = "*"
pytest-xdist = "*"
pytest-cov = "*"
staticx = "*"
staticx = [
{ version = "*", platform = "linux" },
]
pyinstaller = "*"
boto3-stubs = {extras = ["s3"], version = "*"}
pytest-mock = "*"
Expand All @@ -45,7 +47,7 @@ line_length = 79

[tool.black]
line-length = 79
target-version = ['py310']
target-version = ['py311']

[tool.pytest.ini_options]
markers = [
Expand Down
32 changes: 16 additions & 16 deletions sagemaker_shim/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from zipfile import BadZipFile

import boto3
from pydantic import BaseModel, validator
from pydantic import BaseModel, ConfigDict, field_validator

from sagemaker_shim.exceptions import ZipExtractionError
from sagemaker_shim.logging import STDOUT_LEVEL
Expand Down Expand Up @@ -45,16 +45,16 @@ def validate_bucket_name(v: str) -> str:
class InferenceIO(BaseModel):
"""A single input or output file for an inference job"""

model_config = ConfigDict(frozen=True)

relative_path: Path
bucket_name: str
bucket_key: str
decompress: bool = False

class Config:
frozen = True

@validator("bucket_name")
def validate_bucket_name(cls, v: str) -> str: # noqa:B902
@field_validator("bucket_name")
@classmethod
def validate_bucket_name(cls, v: str) -> str:
return validate_bucket_name(v)

def local_file(self, path: Path) -> Path:
Expand Down Expand Up @@ -110,25 +110,24 @@ def upload(self, *, output_path: Path, s3_client: S3Client) -> None:


class InferenceResult(BaseModel):
model_config = ConfigDict(frozen=True)

return_code: int
outputs: list[InferenceIO]
sagemaker_shim_version: str = version("sagemaker-shim")

class Config:
frozen = True


class InferenceTask(BaseModel):
model_config = ConfigDict(frozen=True)

pk: str
inputs: list[InferenceIO]
output_bucket_name: str
output_prefix: str

class Config:
frozen = True

@validator("output_prefix")
def validate_prefix(cls, v: str) -> str: # noqa:B902
@field_validator("output_prefix")
@classmethod
def validate_prefix(cls, v: str) -> str:
if not v:
raise ValueError("Prefix cannot be blank")

Expand All @@ -137,8 +136,9 @@ def validate_prefix(cls, v: str) -> str: # noqa:B902

return v

@validator("output_bucket_name")
def validate_bucket_name(cls, v: str) -> str: # noqa:B902
@field_validator("output_bucket_name")
@classmethod
def validate_bucket_name(cls, v: str) -> str:
return validate_bucket_name(v)

@staticmethod
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[mypy]
python_version = 3.10
python_version = 3.11
plugins = pydantic.mypy
strict = True

Expand Down
8 changes: 5 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import subprocess
import sys
from pathlib import Path

import pytest
Expand All @@ -9,9 +10,10 @@

def pytest_sessionstart(session):
"""https://docs.pytest.org/en/latest/reference/reference.html#_pytest.hookspec.pytest_sessionstart"""
subprocess.check_call(
["make", "-C", Path(__file__).parent.parent / "dist", "all"]
)
if sys.platform == "linux":
subprocess.check_call(
["make", "-C", Path(__file__).parent.parent / "dist", "all"]
)


@pytest.fixture
Expand Down
15 changes: 14 additions & 1 deletion tests/test_container_image.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
from contextlib import contextmanager
from importlib.metadata import version
from time import sleep
Expand Down Expand Up @@ -103,6 +104,9 @@ def container():


@pytest.mark.container
@pytest.mark.skipif(
sys.platform != "linux", reason="does not run outside linux"
)
def test_container_responds_to_ping():
response = httpx.get("http://localhost:8080/ping")

Expand All @@ -113,6 +117,9 @@ def test_container_responds_to_ping():


@pytest.mark.container
@pytest.mark.skipif(
sys.platform != "linux", reason="does not run outside linux"
)
def test_container_responds_to_execution_parameters():
response = httpx.get("http://localhost:8080/execution-parameters")

Expand All @@ -124,6 +131,9 @@ def test_container_responds_to_execution_parameters():


@pytest.mark.container
@pytest.mark.skipif(
sys.platform != "linux", reason="does not run outside linux"
)
def test_invocations_endpoint():
# To receive inference requests, the container must have a web server
# listening on port 8080 and must accept POST requests to the
Expand All @@ -149,11 +159,14 @@ def test_invocations_endpoint():


@pytest.mark.container
@pytest.mark.skipif(
sys.platform != "linux", reason="does not run outside linux"
)
def test_alpine_image():
# https://github.com/JonathonReinhart/staticx/issues/143
host_port = 8081
with _container(
base_image="python:3.10-alpine",
base_image="python:3.11-alpine",
host_port=host_port,
cmd=["python", "-c", "print('hello_world')"],
):
Expand Down
8 changes: 4 additions & 4 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ def test_blank_prefix():
pk="test", inputs=[], output_bucket_name="test", output_prefix=""
)

assert str(error) == (
"<ExceptionInfo ValidationError(model='InferenceTask', "
"errors=[{'loc': ('output_prefix',), "
"'msg': 'Prefix cannot be blank', 'type': 'value_error'}]) tblen=2>"
assert str(error).startswith(
"<ExceptionInfo 1 validation error for InferenceTask\n"
"output_prefix\n Value error, Prefix cannot be blank "
"[type=value_error, input_value='', input_type=str]\n"
)


Expand Down
4 changes: 4 additions & 0 deletions tests/test_patch_image.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import io
import sys
from time import sleep

import docker
Expand Down Expand Up @@ -43,6 +44,9 @@ def registry():


@pytest.mark.registry
@pytest.mark.skipif(
sys.platform != "linux", reason="does not run outside linux"
)
def test_patch_image(registry):
repo = registry[0]
client = registry[1]
Expand Down