[build-system] requires = ["setuptools>=68", "wheel"] build-backend = "setuptools.build_meta" [project] name = "ministack" version = "1.5.39" description = "Free, open-source local AWS emulator — drop-in LocalStack replacement" readme = "README.md" license = { file = "LICENSE" } requires-python = ">=3.10" keywords = ["aws", "localstack", "testing", "s3", "sqs", "dynamodb", "local-dev"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Testing", "Topic :: Internet", ] dependencies = [ "hypercorn>=0.18.0", "pyyaml>=6.0", "defusedxml>=0.7", # IAM enforcement reads request/response shapes out of botocore's service # models to map a wire request to its IAM action. Without it that lookup # finds nothing and AUTH=true would allow what it cannot classify, so this # is a runtime dependency rather than a dev one. Pinned to the version the # images carry. "botocore==1.43.124", # Step Functions JSONata expressions (QueryLanguage: JSONata) are evaluated # by this pure-Python port of the reference jsonata-js engine, which AWS # documents Step Functions as implementing per the JSONata 2.0.6 spec. Pure # Python, no transitive dependencies. "jsonata-python>=0.7.0", # AppSync queries are parsed, validated and executed by the reference Python # GraphQL implementation rather than by regular expressions. Pure Python, no # transitive dependencies. Pinned: a parser change is a behaviour change. "graphql-core==3.2.12", ] [project.optional-dependencies] full = [ "duckdb>=0.10.0", "docker>=7.0.0", "cryptography>=41.0", "psycopg2-binary>=2.9", "pymysql>=1.1", "asyncssh>=2.14", "aws-sam-translator>=1.90", ] # Exactly what CI installs to run the test suite — kept separate from `dev` # (which also carries linters and type stubs) so the workflow has one name to # install instead of an inline package list that drifts from this file. test = [ "boto3>=1.34", "pytest>=8.0", "pytest-xdist>=3.6", "duckdb>=0.10.0", "docker>=7.0.0", "cbor2>=5.4.0", "cryptography>=41.0", "psycopg2-binary>=2.9", "pymysql>=1.1", "aws-sam-translator>=1.90", "websockets>=12.0", ] dev = [ "boto3>=1.34", "pytest>=8.0", "pytest-xdist>=3.6", "pytest-cov>=5.0", "duckdb>=0.10.0", "docker>=7.0.0", "cryptography>=41.0", "psycopg2-binary>=2.9", "pymysql>=1.1", "ruff>=0.4", "mypy-boto3-lambda (>=1.42.85,<2.0.0)", "asyncssh>=2.14", "websockets>=12.0", "aws-sam-translator>=1.90", ] [project.urls] Homepage = "https://github.com/ministackorg/ministack" Repository = "https://github.com/ministackorg/ministack" Issues = "https://github.com/ministackorg/ministack/issues" [project.scripts] ministack = "ministack.app:main" [tool.setuptools.packages.find] include = ["ministack*"] [tool.pytest.ini_options] testpaths = ["tests"] python_files = ["test_*.py"] python_functions = ["test_*"] addopts = "--dist=loadfile" markers = [ "auth_contract: SDK/HTTP permission contracts run against both server AUTH modes", "serial: tests that mutate global server state and must run alone", "data_plane: tests that require live Docker-backed service behavior", ] [tool.ruff] line-length = 120 target-version = "py310" [tool.ruff.lint] select = ["E", "F", "I"] ignore = [ "E501", # line too long — XML templates and service tables make this impractical "E402", # module import not at top — intentional lazy imports in service files "F811", # redefined while unused — needs manual review "F841", # unused variable — needs manual review "E741", # ambiguous variable name — too noisy for emulator code "F601", # multi-value repeated key — needs manual review ] [tool.ruff.lint.per-file-ignores] "ministack/services/dynamodb.py" = ["E701", "E702"] # compact tokenizer style is intentional "ministack/services/lambda_svc.py" = ["E701", "E702"] # compact tokenizer style is intentional [tool.coverage.run] source = ["ministack"] omit = ["tests/*"]