From c7197c70ee64b3c4cd4f0f66d26a5d0c8e1c0a1b Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Thu, 15 Aug 2024 13:27:08 -0700 Subject: [PATCH] STASH --- .vscode/launch.json | 2 +- pyproject.toml | 143 +++++++++++++------------ src/sentry/models/grouphash.py | 12 +++ src/sentry/models/grouphashmetadata.py | 9 ++ tests/conftest.py | 28 +++++ tools/flake8_plugin.py | 16 +++ 6 files changed, 138 insertions(+), 72 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 21a73362cce429..08f214430fcac3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -59,7 +59,7 @@ "type": "python", "request": "launch", "module": "pytest", - "args": ["--verbosity", "2", "${file}"], + "args": ["--verbosity", "2", "--reuse-db", "${file}"], "django": true, "env": { "SENTRY_MODEL_MANIFEST_FILE_PATH": "./model-manifest.json" diff --git a/pyproject.toml b/pyproject.toml index b2f6e5b65d9805..5d1efac3b636b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,84 +1,85 @@ [tool.black] -# File filtering is taken care of in pre-commit. -line-length = 100 -target-version = ['py311'] + # File filtering is taken care of in pre-commit. + line-length = 100 + target-version = ['py311'] [tool.isort] -profile = "black" -line_length = 100 -lines_between_sections = 1 -known_first_party = "sentry" -skip = "migrations" + profile = "black" + line_length = 100 + lines_between_sections = 1 + known_first_party = "sentry" + skip = "migrations" [tool.pytest.ini_options] -python_files = "test_*.py sentry/testutils/*" -# note: When updating the traceback format, make sure to update .github/pytest.json -# We don't use the celery pytest plugin. -addopts = "--tb=short -p no:celery --nomigrations" -# TODO: --import-mode=importlib will become the default soon, -# currently we have a few relative imports that don't work with that. -markers = [ - "snuba: test requires access to snuba", - "snuba_ci: test is run in snuba ci", - "sentry_metrics: test requires access to sentry metrics", - "symbolicator: test requires access to symbolicator", - "querybuilder: smoke tests for QueryBuilders", -] -filterwarnings = [ - # Consider all warnings to be errors other than the ignored ones. - "error", + python_files = "test_*.py sentry/testutils/*" + # note: When updating the traceback format, make sure to update .github/pytest.json + # We don't use the celery pytest plugin. + addopts = "--tb=short -p no:celery --nomigrations" + # TODO: --import-mode=importlib will become the default soon, + # currently we have a few relative imports that don't work with that. + markers = [ + "snuba: test requires access to snuba", + "snuba_ci: test is run in snuba ci", + "sentry_metrics: test requires access to sentry metrics", + "symbolicator: test requires access to symbolicator", + "querybuilder: smoke tests for QueryBuilders", + "only: if this appears on any test in a file, only run tests with this marker", + ] + filterwarnings = [ + # Consider all warnings to be errors other than the ignored ones. + "error", - # phabricator uses `pkg_resources` apis - "ignore:pkg_resources is deprecated as an API", + # phabricator uses `pkg_resources` apis + "ignore:pkg_resources is deprecated as an API", - # this warning in protobuf causes a segfault in 3.12+ protocolbuffers/protobuf#15077 - "ignore:Type google\\._upb.*", + # this warning in protobuf causes a segfault in 3.12+ protocolbuffers/protobuf#15077 + "ignore:Type google\\._upb.*", - # The following warning filters are for pytest only. - "ignore:.*sentry.digests.backends.dummy.DummyBackend.*:sentry.utils.warnings.UnsupportedBackend", + # The following warning filters are for pytest only. + "ignore:.*sentry.digests.backends.dummy.DummyBackend.*:sentry.utils.warnings.UnsupportedBackend", - # pytest has not yet implemented the replacement for this yet - "ignore:The --looponfail command line argument.*", -] -looponfailroots = ["src", "tests"] + # pytest has not yet implemented the replacement for this yet + "ignore:The --looponfail command line argument.*", + ] + looponfailroots = ["src", "tests"] [tool.mypy] -python_version = "3.11" -mypy_path = ["fixtures/stubs-for-mypy"] -plugins = [ - "pydantic.mypy", - "mypy_django_plugin.main", - "tools.mypy_helpers.plugin", -] -files = ["."] -exclude = ["^.venv/", "^venv/", "^self-hosted/"] + python_version = "3.11" + mypy_path = ["fixtures/stubs-for-mypy"] + plugins = [ + "pydantic.mypy", + "mypy_django_plugin.main", + "tools.mypy_helpers.plugin", + ] + files = ["."] + exclude = ["^.venv/", "^venv/", "^self-hosted/"] -# minimal strictness settings -check_untyped_defs = true -no_implicit_reexport = true -warn_unreachable = true -warn_unused_configs = true -warn_unused_ignores = true -warn_redundant_casts = true -enable_error_code = ["ignore-without-code", "redundant-self"] + # minimal strictness settings + check_untyped_defs = true + no_implicit_reexport = true + warn_unreachable = true + warn_unused_configs = true + warn_unused_ignores = true + warn_redundant_casts = true + enable_error_code = ["ignore-without-code", "redundant-self"] [tool.django-stubs] -django_settings_module = "sentry.conf.server_mypy" + django_settings_module = "sentry.conf.server_mypy" # these have py.typed but incorrect types [[tool.mypy.overrides]] -module = [ - # TODO: these cause type errors when followed - "snuba_sdk.*", -] -follow_imports = "skip" + module = [ + # TODO: these cause type errors when followed + "snuba_sdk.*", + ] + follow_imports = "skip" # python3 -m tools.mypy_helpers.make_stub_ignores # begin: missing 3rd party stubs # - add .pyi files to fixtures/stubs-for-mypy # - or find a 3rd party stub [[tool.mypy.overrides]] -module = [ + module = [ "boto3.*", "botocore.client.*", "botocore.exceptions.*", @@ -104,16 +105,16 @@ module = [ "statsd.*", "u2flib_server.model.*", "unidiff.*", -] -ignore_missing_imports = true -# end: missing 3rd party stubs + ] + ignore_missing_imports = true + # end: missing 3rd party stubs # python3 -m tools.mypy_helpers.make_module_ignores # begin: sentry modules with typing issues # - remove the module from the list and fix the issues! # - python3 -m tools.mypy_helpers.find_easiest_modules [[tool.mypy.overrides]] -module = [ + module = [ "sentry.api.base", "sentry.api.bases.organization_events", "sentry.api.bases.organization_request_change", @@ -424,8 +425,8 @@ module = [ "tests.sentry.eventstore.test_base", "tests.sentry.grouping.test_result", "tests.sentry.issues.test_utils", -] -disable_error_code = [ + ] + disable_error_code = [ "arg-type", "assignment", "attr-defined", @@ -443,12 +444,12 @@ disable_error_code = [ "union-attr", "unreachable", "var-annotated", -] -# end: sentry modules with typing issues + ] + # end: sentry modules with typing issues # begin: stronger typing [[tool.mypy.overrides]] -module = [ + module = [ "sentry.api.endpoints.issues.*", "sentry.api.helpers.deprecation", "sentry.api.helpers.source_map_helper", @@ -610,7 +611,7 @@ module = [ "tests.sentry.types.test_actor", "tests.sentry.types.test_region", "tools.*", -] -disallow_any_generics = true -disallow_untyped_defs = true -# end: stronger typing + ] + disallow_any_generics = true + disallow_untyped_defs = true + # end: stronger typing diff --git a/src/sentry/models/grouphash.py b/src/sentry/models/grouphash.py index 8fff104a138799..05e57973dcc6e3 100644 --- a/src/sentry/models/grouphash.py +++ b/src/sentry/models/grouphash.py @@ -52,3 +52,15 @@ def metadata(self) -> GroupHashMetadata | None: return self._metadata except Exception: return None + + # def delete(self, *args, **kwargs): + # # raise Exception("wtf") + # print("\n\n********************\n\n") + # print("\n\n********************\n\n") + # print("\n\n********************\n\n") + # print("\n\n********************\n\n") + # breakpoint() + # metadata = self.metadata + # if metadata: + # metadata.delete() + # return super().delete(*args, **kwargs) diff --git a/src/sentry/models/grouphashmetadata.py b/src/sentry/models/grouphashmetadata.py index 83a69d706028f2..75eeb78593081a 100644 --- a/src/sentry/models/grouphashmetadata.py +++ b/src/sentry/models/grouphashmetadata.py @@ -24,4 +24,13 @@ class Meta: def group_id(self) -> int | None: return self.grouphash.group_id + # def repr(self): + # self.group_id = self.grouphash.group_id + # return sane_repr("grouphash_id", "group_id") + __repr__ = sane_repr("grouphash_id", "group_id") + # __repr__ = sane_repr("grouphash_id") + + # def __repr__(self)-> str: + # self.group_id = self.grouphash.group_id + # default_repr = sane_repr("grouphash_id", "group_id") diff --git a/tests/conftest.py b/tests/conftest.py index c78b521c930c0a..6e4c882a8289d7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,6 @@ +import os from collections.abc import MutableMapping +from typing import Any import psutil import pytest @@ -116,3 +118,29 @@ def check_leaked_responses_mocks(): f"`responses` were leaked outside of the test context:\n{leaked_s}" f"(make sure to use `@responses.activate` or `with responses.mock:`)" ) + + +def pytest_collection_modifyitems( + session: pytest.Session, config: Any, items: list[pytest.Item] +) -> None: + """ + Enable the use of `@pytest.mark.only` for running just the tests with this decorator. Works + best when running tests in a single file. + + Note: Should only be used in development! + + Inspired by https://stackoverflow.com/a/70607961 + """ + + # There's a lint rule in place to keep people from committing a `@pytest.mark.only` + # decorator (and to keep CI from passing if it finds one), but just in case... + if os.environ.get("GITHUB_ACTIONS"): + return + + tests_with_only_marker = [i for i in items if i.get_closest_marker("only")] + + if tests_with_only_marker: + print( # noqa: S002 + f"\nFound `pytest.mark.only`. Running {len(tests_with_only_marker)} of {len(items)} tests." + ) + items[:] = tests_with_only_marker diff --git a/tools/flake8_plugin.py b/tools/flake8_plugin.py index f29f012913e83e..93c5dc49d1dbd5 100644 --- a/tools/flake8_plugin.py +++ b/tools/flake8_plugin.py @@ -33,6 +33,10 @@ S011_msg = "S011 Use override_options(...) instead to ensure proper cleanup" +S012_msg = ( + "S012 Remember to remove all instances of `pytest.mark.only` before pushing to production." +) + class SentryVisitor(ast.NodeVisitor): def __init__(self, filename: str) -> None: @@ -144,6 +148,18 @@ def visit_Call(self, node: ast.Call) -> None: if keyword.arg == "SENTRY_OPTIONS": self.errors.append((keyword.lineno, keyword.col_offset, S011_msg)) + def visit_FunctionDef(self, node: ast.FunctionDef) -> None: + for decorator in node.decorator_list: + if ( + isinstance(decorator, ast.Attribute) + and decorator.attr == "only" + and isinstance(decorator.value, ast.Attribute) + and decorator.value.attr == "mark" + and isinstance(decorator.value.value, ast.Name) + and decorator.value.value.id == "pytest" + ): + self.errors.append((node.lineno, node.col_offset, S012_msg)) + self.generic_visit(node)