Skip to content

Bugfix Config.from_object on Config instances (closes #244)#355

Open
jbbqqf wants to merge 1 commit into
pgjones:mainfrom
jbbqqf:fix/244-config-from-object-writeonly-property
Open

Bugfix Config.from_object on Config instances (closes #244)#355
jbbqqf wants to merge 1 commit into
pgjones:mainfrom
jbbqqf:fix/244-config-from-object-writeonly-property

Conversation

@jbbqqf
Copy link
Copy Markdown

@jbbqqf jbbqqf commented May 22, 2026

Summary

Config.from_object raises AttributeError: property 'cert_reqs' of 'Config' object has no getter when handed a populated Config() instance — i.e. when a user runs

hypercorn --config python:my_module.config app:app

with my_module.config = Config(); my_module.config.bind = "...". This is the documented use case in the from_object docstring.

Root cause: from_object iterates dir(instance) and calls getattr on every name, but cert_reqs is intentionally a write-only property (the deprecation alias for verify_mode). The getattr raises before the dict-comprehension can decide what to do.

Fix: skip names whose getter raises AttributeError. The deprecation alias is preserved (it still works when set via attribute write), but no longer crashes the loader.

Fixes #244.

Changes

  • src/hypercorn/config.py — convert from_object's dict comprehension to a loop that swallows AttributeError; comment cites the issue.
  • tests/test_config.pytest_config_from_object_accepts_config_instance round-trips a populated Config() and asserts the values survive.

Reproduce BEFORE/AFTER yourself (copy-paste)

# --- one-time setup ---
rm -rf /tmp/hc-244 && git clone https://github.com/pgjones/hypercorn.git /tmp/hc-244 && cd /tmp/hc-244
python3.11 -m venv .venv && source .venv/bin/activate
pip install -e . pytest pytest-asyncio pytest-trio trio httpx hypothesis mock

# --- BEFORE: origin/main, expect AttributeError ---
git checkout origin/main
python -c "
from hypercorn.config import Config
c = Config(); c.bind = '0.0.0.0:8080'
print(Config.from_object(c).bind)
"
# Expected: AttributeError: property 'cert_reqs' of 'Config' object has no getter

# --- AFTER: this branch, expect ['0.0.0.0:8080'] ---
git fetch https://github.com/jbbqqf/hypercorn.git fix/244-config-from-object-writeonly-property
git checkout FETCH_HEAD
python -c "
from hypercorn.config import Config
c = Config(); c.bind = '0.0.0.0:8080'
print(Config.from_object(c).bind)
"
# Expected: ['0.0.0.0:8080']

What I ran locally

$ pytest tests/test_config.py -v
========== 14 passed in 0.02s ==========

$ pytest -x --timeout=30 -q
197 passed in 6.29s

$ black --check src/hypercorn/config.py tests/test_config.py
2 files would be left unchanged.

$ isort --check src/hypercorn tests
(no output — clean)

$ flake8 src/hypercorn/ tests/
(no output — clean)

The new regression test fails on origin/main with the exact AttributeError cited in #244 and passes on the fix branch.

Edge cases

# Scenario Source Expected Verified by
1 Module-as-config (existing supported form) from_object("module") unchanged behaviour test_config_from_object (existing)
2 Populated Config() instance (the bug) c = Config(); c.bind = [...]; from_object(c) round-trips test_config_from_object_accepts_config_instance (new)
3 Plain object with mixed-readability properties any class with @property write-only property silently skipped covered by (2) — cert_reqs is exactly this
4 Module attribute (ModuleType filter) from_object(...) on a module that imports os os skipped (unchanged) preserved isinstance(value, ModuleType) check

Risk / blast radius

Single function, single behavioural change: previously-unreachable code paths now reach from_mapping. Nothing in the project's own test suite regressed (197 / 197). The only observable difference for existing users is that from_object now tolerates write-only properties — that cannot break a working caller.


PR drafted with assistance from Claude Code (Anthropic). The change was reviewed manually against hypercorn's source. The reproducer block above is the one I used during development; reviewers can paste it verbatim.

`Config.from_object` iterates `dir(instance)` and reads every attribute,
which raises `AttributeError: property 'cert_reqs' of 'Config' object has
no getter` when the instance is a `Config()` itself, because
`cert_reqs = property(None, set_cert_reqs)` is intentionally write-only
to deprecate the name.

Skip names whose getter raises AttributeError so that

    hypercorn --config python:my_module.config

is usable when the module exposes a populated `Config` instance.

Closes pgjones#244.
Copy link
Copy Markdown

@TomiBelan TomiBelan left a comment

Choose a reason for hiding this comment

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

This feels very unnecessarily complicated. Wouldn't it be easier and more reliable to just add this?

if isinstance(instance, cls):
    return instance

Note: I am a random passerby. My "request changes" is not official. You can decide to ignore it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

error hypercorn --config python:hypercorn_config.config

2 participants