Skip to content

Remove enum usage for header/trailer in smithy-http and aws-sdk-signers#670

Merged
ubaskota merged 3 commits intosmithy-lang:developfrom
ubaskota:enum_usage_header
Mar 31, 2026
Merged

Remove enum usage for header/trailer in smithy-http and aws-sdk-signers#670
ubaskota merged 3 commits intosmithy-lang:developfrom
ubaskota:enum_usage_header

Conversation

@ubaskota
Copy link
Copy Markdown
Contributor

Issue #, if available:

Description of changes:
FieldPosition was an enum, which meant any library implementing the Field protocol had to import smithy-http just to reference the enum values. Switch to Literal["header", "trailer"] so that implementations can pass equality checks using plain strings without depending on smithy-http. Also change identity checks (is) to equality (==) to ensure correctness with string literals.

Testing

  • Updated the tests to reflect the changes and verified that all tests pass.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@ubaskota ubaskota requested a review from a team as a code owner March 26, 2026 18:36
Copy link
Copy Markdown
Contributor

@jonathan343 jonathan343 left a comment

Choose a reason for hiding this comment

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

Thanks Ujjwal!

I left a few comments. Let me know if you have any questions!

With more adoption, I'd normally want to have a transition period where we continue to support enum usage, but I searched through GitHub and don't see anyone using Field or FieldPosition classes directly. This approach seems fine to me!

):
self.name = name
self.values: list[str] = list(values) if values is not None else []
self.kind = kind
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should add some sort of runtime validation for this. It should only be possible for someone to create an instance of Field with "header" or "trailer". However, with this PR, the following is possible:

>>> from aws_sdk_signers._http import Field
>>> Field(name="foo", values=["bar"], kind="baz")
Field(name='foo', value=['bar'], kind='baz')

One option is to do create a frozen set like _VALID_FIELD_POSITIONS = frozenset(("header", "trailer")) then do validation at init time:

if kind not in _VALID_FIELD_POSITIONS:
    raise ValueError(f"Unknown field kind: {kind}")

However, now we have to maintain this list in two (really four because of the duplication across packages) separate places.

Instead, maybe we can derive valid field values from the FieldPosition type itself like _VALID_FIELD_POSITIONS = frozenset(get_args(interfaces_http.FieldPosition))

assert field.values == ["fval1", "fval2"]
assert field.as_string() == "fval1,fval2"
assert field.as_tuples() == [("fname", "fval1"), ("fname", "fval2")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If/when we add runtime validation, we should add a test like test_field_invalid_kind to ensure we're raising an appropriate error for this case. Something like:

def test_field_invalid_kind() -> None:
    with pytest.raises(ValueError, match="Unknown field kind"):
        Field(name="fname", kind="metadata")

name: str,
values: Iterable[str] | None = None,
kind: FieldPosition = FieldPosition.HEADER,
kind: FieldPosition = "header",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same suggestion here as with aws-sdk-signers: We should add some runtime validation.

assert field.as_string() == "fval1, fval2"
assert field.as_tuples() == [("fname", "fval1"), ("fname", "fval2")]


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same here about the test_field_invalid_kind test

@@ -0,0 +1,4 @@
{
"type": "breaking",
"description": "Replace FieldPosition enum with a Literal type"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This changelog entry description feels insufficient to me. As a user, I usually want to know what to do when there is a breaking change. I've provided a description below I feel is more adequate. (note: I also like linking PRs, but you can omit if you want).

Suggested change
"description": "Replace FieldPosition enum with a Literal type"
"description": "Replace `FieldPosition` enum values with string literals for `Field.kind`. Use \"header\" and \"trailer\" instead of `FieldPosition.HEADER` and `FieldPosition.TRAILER`. ([#670](https://github.com/smithy-lang/smithy-python/pull/670))"

@@ -0,0 +1,4 @@
{
"type": "breaking",
"description": "Replace FieldPosition enum with a Literal type"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same suggestion here:

Suggested change
"description": "Replace FieldPosition enum with a Literal type"
"description": "Replace `FieldPosition` enum values with string literals for `Field.kind`. Use \"header\" and \"trailer\" instead of `FieldPosition.HEADER` and `FieldPosition.TRAILER`. ([#670](https://github.com/smithy-lang/smithy-python/pull/670))"

@ubaskota ubaskota merged commit b2fad24 into smithy-lang:develop Mar 31, 2026
4 checks passed
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.

2 participants