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

test: Restore coverage measurement #16

Merged
merged 2 commits into from
Feb 23, 2024
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
4 changes: 3 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
__pycache__
.coverage*
.env
.env.sample
.ipynb_checkpoints
.mypy_cache
.pytest_cache
.ruff_cache
.venv
coverage
htmlcov
mypy-results
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
uses: addnab/docker-run-action@v3
with:
image: amazon/aws-glue-libs:glue_libs_4.0.0_image_01
options: --volume ${{ github.workspace }}:/home/glue_user/workspace
options: --volume ${{ github.workspace }}:/home/glue_user/workspace --env AWS_REGION=us-east-1
run: |
pip3 install --no-warn-script-location --user --upgrade pip==24.0
pip3 install --no-warn-script-location --user -r requirements.txt
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
__pycache__
.coverage*
.env
.ipynb_checkpoints
.mypy_cache
.pytest_cache
.ruff_cache
.venv
mypy-results
coverage
htmlcov
mypy-results
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@
"python.analysis.diagnosticSeverityOverrides": {
"reportGeneralTypeIssues": "warning"
},
"python.testing.pytestEnabled": true
"python.testing.pytestEnabled": true,
"autoDocstring.docstringFormat": "numpy-notypes",
}
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ else
endif


.PHONY: coverage
coverage: ## Generate test coverage HTML report
ifeq ($(PLATFORM), docker)
@pytest --cov=src --cov=glue_utils --cov-branch --cov-report=term
@coverage html
else
@$(COMPOSE_RUN) -c "make coverage"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (llm): The recursive call to make coverage within the Docker condition might lead to an infinite loop if the PLATFORM variable remains set to docker within the Docker environment. Consider verifying or setting a different mechanism to avoid potential infinite recursion.

endif


.PHONY: checks
checks: format typecheck

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ format Format project source code
lint Check source code for common errors
typecheck Check type annotations
test Run automated tests
coverage Generate test coverage HTML report
shell Start a bash shell session inside the container
clean-notebooks Removes output cells from Jupyter notebooks
pyspark Start a Spark shell session
Expand Down
57 changes: 33 additions & 24 deletions glue_utils/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,50 @@

from awsglue.context import GlueContext
from awsglue.job import Job
from pyspark import SparkConf
from pyspark.sql import SparkSession
from pyspark import SparkConf, SparkContext


class ManagedGlueContext(ContextDecorator):
options: dict[str, str]
job_options: dict[str, str]
spark_conf: SparkConf | None
job: Job

def __init__(self, options: dict[str, str] | None = None) -> None:
self.options = options or {}
def __init__(
self,
*,
job_options: dict[str, str] | None = None,
spark_conf: SparkConf | None = None,
) -> None:
"""Creates a context manager that wraps a GlueContext and
ensures that Job.commit() is called.

Parameters
----------
init_options, optional
Dictionary of key-value pairs to pass to Job.init().
Defaults to None.
conf, optional
Custom SparkConf to use with SparkContext.getOrCreate().
Defaults to None.
"""
self.job_options = job_options or {}
self.spark_conf = spark_conf

super().__init__()

def __enter__(self) -> GlueContext:
glue_context = self.create_glue_context(self.create_spark_session())
job_name = self.job_options.get("JOB_NAME", "")

conf = self.spark_conf or SparkConf()
conf = conf.setAppName(job_name)

self.job = Job(glue_context)
self.job.init(self.options.get("JOB_NAME", ""), self.options)
spark_context = SparkContext.getOrCreate(conf)
self.glue_context = GlueContext(spark_context)

return glue_context
self.job = Job(self.glue_context)
self.job.init(job_name, self.job_options)

return self.glue_context

def __exit__(
self,
Expand All @@ -34,18 +58,3 @@ def __exit__(
self.job.commit()

return cast(bool, False) # noqa: FBT003

def create_spark_conf(self) -> SparkConf:
return SparkConf()

def create_spark_session(self) -> SparkSession:
conf = self.create_spark_conf()

return (
SparkSession.builder.appName(name=self.options.get("JOB_NAME", ""))
.config(conf=conf)
.getOrCreate()
)

def create_glue_context(self, spark_session: SparkSession) -> GlueContext:
return GlueContext(spark_session)
87 changes: 86 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 23 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pip = "^24.0"
pytest-randomly = "^3.15.0"
pytest = "^8.0.1"
ruff = "^0.2.2"
pytest-cov = "^4.1.0"

[tool.poetry.group.runtime.dependencies]
# The "runtime" dependency group refers to dependencies that already
Expand Down Expand Up @@ -80,4 +81,25 @@ disallow_untyped_defs = false
disallow_untyped_calls = false

[tool.pytest.ini_options]
filterwarnings = ["ignore::DeprecationWarning"]
filterwarnings = [
"ignore::DeprecationWarning",
"ignore::FutureWarning:.*pyspark.*",
]

[tool.coverage.run]
omit = ["**/test_*.py"]

[tool.coverage.report]
skip_empty = true
exclude_also = [
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]
Loading