adobe / adobe/pconfigs

@pproperty not enforced when derived @pconfig narrows a field's type

Open
#8 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Python
Stars
1
Forks
1
PR merge metrics
No merged PRs in 30d

Description

**Summary**

When a derived `@pconfig` class narrows a field's type annotation and the base class defines a `@pproperty` for that field, pconfigs requires the user to write a `@pproperty` override in the derived class that upgrades the incoming type. If they do not, a config instance file that passes the old base type will be silently accepted at construction time but crash at runtime when code accesses a field that only exists on the derived type.

This is a feature request for pconfigs to auto-generate that upgrading pproperty, or to raise an actionable error at class-definition time when the narrowing is detected without a corresponding override.

**Motivation**

A derived config class that narrows a field type signals an invariant: objects constructed from that config should always receive the derived type. But the base pproperty runs and returns the user-provided value unchanged, so a plain base-typed value passes through silently. The failure surfaces only at runtime, far from the config definition. There is no signal at class-definition or construction time that a pproperty override is required.

**Proposed behavior**

When pconfigs detects that a derived config class narrows the declared type of a field that has a `@pproperty` in a base class, and the derived class does not define its own `@pproperty` for that field, it should either (a) automatically synthesize a pproperty that upgrades the base type to the declared derived type, or (b) raise an error at class-definition time.

```python
from pconfigs import pconfig, pconfiged, pproperty, pinputs, pdefaults
from typing import Optional

@pconfig
class WidgetConfig:
color: Optional[str]

@pconfig
class FancyWidgetConfig(WidgetConfig):
size: Optional[int]

pdefaults += WidgetConfig(color=None)
pdefaults += FancyWidgetConfig(color=None, size=None)

@pconfiged
class System:
config: SystemConfig

@pconfig(constructs=System)
class SystemConfig:
widget_config: WidgetConfig

@pproperty
def widget_config(self) -> WidgetConfig:
return pinputs(self).widget_config

pdefaults += SystemConfig(widget_config=pdefaults(WidgetConfig))

@pconfiged
class FancySystem(System):
config: FancySystemConfig

@pconfig(constructs=FancySystem)
class FancySystemConfig(SystemConfig):
widget_config: FancyWidgetConfig # narrowed — but no pproperty override

pdefaults += FancySystemConfig(widget_config=pdefaults(FancyWidgetConfig))

# User passes a plain WidgetConfig where FancyWidgetConfig is declared.
# The base pproperty accepts it silently. Downstream code that accesses
# .size crashes at runtime with AttributeError.
config = FancySystemConfig(widget_config=WidgetConfig(color="red"))
system = config.construct()
print(system.config.widget_config.size) # AttributeError: 'WidgetConfig' has no attribute 'size'
```

Proposed: `FancySystemConfig(widget_config=WidgetConfig(...)).construct()` should raise at construction time with a message like:

> `FancySystemConfig` narrows field `widget_config` to `FancyWidgetConfig`, but inherits a `@pproperty` from `SystemConfig` that returns `WidgetConfig`. Define a `@pproperty` override in `FancySystemConfig` to enforce the narrowed type.

**Current workaround**

The derived config class must manually define a `@pproperty` override that upgrades the user-provided base type to the derived type. This is easy to forget and there is no warning when it is omitted.

Contributor guide

Open the contributing guide

Research direction

Start by tracing how @pconfig, inherited @pproperty methods, and construct() handle declared field types during FancySystemConfig construction. Reproduce the WidgetConfig/FancyWidgetConfig example, then determine whether the project should synthesize an upgrading property or raise the proposed class-definition or construction-time error. The issue names no implementation files or tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.