Created
March 18, 2025 21:58
-
-
Save justinvanwinkle/44d4edfa7c5889e0608102e44c58b168 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def pytest_addoption(parser): | |
""" | |
This hook is used to add custom command-line options to pytest. | |
""" | |
parser.addoption( | |
"--hard-mode", | |
action="store_true", | |
default=False, | |
help="Wire up extra checks" | |
) | |
@pytest.fixture | |
def myoption(request): | |
""" | |
This fixture returns the value of the custom command-line option '--myoption'. | |
""" | |
return request.config.getoption("--myoption") | |
def pytest_configure(config): | |
# Check if the option is enabled. | |
if config.getoption("--hard-mode"): | |
setup_hard_mode() | |
def get_park_modules(): | |
# we need this import just to make sure we imported everything, and not as a side effect | |
import sys | |
import park # noqa: F401 | |
for mod_name, module in sys.modules.items(): | |
if mod_name.startswith("park.") and not mod_name.endswith("_test"): | |
if mod_name == "park.types": | |
continue | |
yield mod_name, module | |
def get_classes(): | |
modules = get_park_modules() | |
for _name, module in modules: | |
for name, obj in vars(module).items(): | |
if ( | |
isinstance(obj, type) | |
and not name.startswith("_") | |
and obj.__module__ == module.__name__ | |
): | |
yield obj | |
def safe_hasattr(obj, name): | |
# Check the instance's __dict__ if it exists. | |
import inspect | |
if hasattr(obj, name): | |
return True | |
dc_fields = getattr(type(obj), '__dataclass_fields__', ()) | |
if name in dc_fields: | |
return True | |
# let it set freely inside of __init__ | |
stack = inspect.stack() | |
for fname in ('__init__', 'reset'): | |
if stack[2].function == fname: | |
return True | |
if stack[2].function == 'setUp' or stack[3].function == 'setUp' or stack[4].function == 'setUp': | |
return True | |
return False | |
def setup_hard_mode(): | |
import traceback | |
import park # noqa: F401 | |
def __setattr__(self, name, value): | |
# Check if the attribute is defined in the class or its parents. | |
allowed = set(['api_model', '_sa_instance_state', '_cached_data', '_parsed_content_type', '__orig_class__', 'lock', '_lock']) | |
if name not in allowed and not safe_hasattr(self, name) and not name.startswith('_AssociationProxy'): | |
msg = f"Cannot set attribute {name!r} on {self.__class__} because it is not defined in class {type(self).__name__}" | |
print(''.join(traceback.format_stack())) | |
print(msg) | |
raise BaseException(msg) | |
object.__setattr__(self, name, value) | |
classes = get_classes() | |
for cls in classes: | |
if cls.__setattr__ == object.__setattr__: | |
try: | |
cls.__setattr__ = __setattr__ | |
except RuntimeError as e: | |
print(e) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment