Server Test Python

Server Test Python

rev. 0b749be6d000fdc7ef59d1bc26f1dce00358d95c

Files changed:

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/python/json_rpc10/__init__.pyi

@@ -7,7 +66,72 @@
   27     27   
        counter: int = 0
   28     28   
   29     29   
    app = App()
   30     30   
    app.context(Context())
   31     31   
   32     32   
    @app.request_middleware
   33     33   
    def request_middleware(request: middleware::Request):
   34     34   
        if request.get_header("x-amzn-id") != "secret":
   35     35   
            raise middleware.MiddlewareException("Unsupported `x-amz-id` header", 401)
   36     36   
          37  +
    # The example tests how servers must support requests
          38  +
    # containing a `Content-Type` header with parameters.
          39  +
    @app.content_type_parameters
          40  +
    def content_type_parameters(input: input::ContentTypeParametersInput, ctx: Context) -> output::ContentTypeParametersOutput:
          41  +
        raise NotImplementedError
          42  +
   37     43   
    # The example tests how requests and responses are serialized when there's
   38     44   
    # no request or response payload because the operation has an empty input
   39     45   
    # and empty output structure that reuses the same shape. While this should
   40     46   
    # be rare, code generators must support this.
   41     47   
    @app.empty_input_and_empty_output
   42     48   
    def empty_input_and_empty_output(input: input::EmptyInputAndEmptyOutputInput, ctx: Context) -> output::EmptyInputAndEmptyOutputOutput:
   43     49   
        raise NotImplementedError
   44     50   
   45     51   
    @app.endpoint_operation
   46     52   
    def endpoint_operation(input: input::EndpointOperationInput, ctx: Context) -> output::EndpointOperationOutput:
@@ -86,92 +145,159 @@
  106    112   
    def simple_scalar_properties(input: input::SimpleScalarPropertiesInput, ctx: Context) -> output::SimpleScalarPropertiesOutput:
  107    113   
        raise NotImplementedError
  108    114   
  109    115   
    app.run()
  110    116   
    ```
  111    117   
  112    118   
    Any of operations above can be written as well prepending the `async` keyword and
  113    119   
    the Python application will automatically handle it and schedule it on the event loop for you.
  114    120   
    """
  115    121   
         122  +
    def content_type_parameters(self, func: typing.Union[typing.Callable[[json_rpc10.input.ContentTypeParametersInput, Ctx], typing.Union[json_rpc10.output.ContentTypeParametersOutput, typing.Awaitable[json_rpc10.output.ContentTypeParametersOutput]]], typing.Callable[[json_rpc10.input.ContentTypeParametersInput], typing.Union[json_rpc10.output.ContentTypeParametersOutput, typing.Awaitable[json_rpc10.output.ContentTypeParametersOutput]]]]) -> None:
         123  +
        """
         124  +
        Method to register `content_type_parameters` Python implementation inside the handlers map.
         125  +
        It can be used as a function decorator in Python.
         126  +
        """
         127  +
        ...
         128  +
         129  +
  116    130   
    def context(self, context: Ctx) -> None:
  117    131   
        """
  118    132   
        Register a context object that will be shared between handlers.
  119    133   
        """
  120    134   
        ...
  121    135   
  122    136   
  123    137   
    def empty_input_and_empty_output(self, func: typing.Union[typing.Callable[[json_rpc10.input.EmptyInputAndEmptyOutputInput, Ctx], typing.Union[json_rpc10.output.EmptyInputAndEmptyOutputOutput, typing.Awaitable[json_rpc10.output.EmptyInputAndEmptyOutputOutput]]], typing.Callable[[json_rpc10.input.EmptyInputAndEmptyOutputInput], typing.Union[json_rpc10.output.EmptyInputAndEmptyOutputOutput, typing.Awaitable[json_rpc10.output.EmptyInputAndEmptyOutputOutput]]]]) -> None:
  124    138   
        """
  125    139   
        Method to register `empty_input_and_empty_output` Python implementation inside the handlers map.

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/python/json_rpc10/input/__init__.pyi

@@ -1,1 +33,40 @@
    1      1   
import json_rpc10.model
    2      2   
import typing
    3      3   
           4  +
class ContentTypeParametersInput:
           5  +
    value: typing.Optional[int]
           6  +
           7  +
    def __init__(self, value: typing.Optional[int] = ...) -> None:
           8  +
        ...
           9  +
          10  +
    4     11   
class EmptyInputAndEmptyOutputInput:
    5     12   
    def __init__(self) -> None:
    6     13   
        ...
    7     14   
    8     15   
    9     16   
class EndpointOperationInput:
   10     17   
    def __init__(self) -> None:
   11     18   
        ...
   12     19   
   13     20   

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/python/json_rpc10/output/__init__.pyi

@@ -1,1 +34,39 @@
    1      1   
import json_rpc10.model
    2      2   
import json_rpc10.types
    3      3   
import typing
    4      4   
           5  +
class ContentTypeParametersOutput:
           6  +
    def __init__(self) -> None:
           7  +
        ...
           8  +
           9  +
    5     10   
class EmptyInputAndEmptyOutputOutput:
    6     11   
    def __init__(self) -> None:
    7     12   
        ...
    8     13   
    9     14   
   10     15   
class EndpointOperationOutput:
   11     16   
    def __init__(self) -> None:
   12     17   
        ...
   13     18   
   14     19   

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/src/error.rs

@@ -318,318 +377,433 @@
  338    338   
                return error.into();
  339    339   
            }
  340    340   
            crate::error::InternalServerError {
  341    341   
                message: error.to_string(),
  342    342   
            }
  343    343   
            .into()
  344    344   
        })
  345    345   
    }
  346    346   
}
  347    347   
         348  +
/// Error type for the `ContentTypeParameters` operation.
         349  +
/// Each variant represents an error that can occur for the `ContentTypeParameters` operation.
         350  +
#[derive(::std::fmt::Debug)]
         351  +
pub enum ContentTypeParametersError {
         352  +
    #[allow(missing_docs)] // documentation missing in model
         353  +
    InternalServerError(crate::error::InternalServerError),
         354  +
}
         355  +
impl ::std::fmt::Display for ContentTypeParametersError {
         356  +
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         357  +
        match &self {
         358  +
            ContentTypeParametersError::InternalServerError(_inner) => _inner.fmt(f),
         359  +
        }
         360  +
    }
         361  +
}
         362  +
impl ContentTypeParametersError {
         363  +
    /// Returns `true` if the error kind is `ContentTypeParametersError::InternalServerError`.
         364  +
    pub fn is_internal_server_error(&self) -> bool {
         365  +
        matches!(&self, ContentTypeParametersError::InternalServerError(_))
         366  +
    }
         367  +
    /// Returns the error name string by matching the correct variant.
         368  +
    pub fn name(&self) -> &'static str {
         369  +
        match &self {
         370  +
            ContentTypeParametersError::InternalServerError(_inner) => _inner.name(),
         371  +
        }
         372  +
    }
         373  +
}
         374  +
impl ::std::error::Error for ContentTypeParametersError {
         375  +
    fn source(&self) -> std::option::Option<&(dyn ::std::error::Error + 'static)> {
         376  +
        match &self {
         377  +
            ContentTypeParametersError::InternalServerError(_inner) => Some(_inner),
         378  +
        }
         379  +
    }
         380  +
}
         381  +
impl ::std::convert::From<crate::error::InternalServerError>
         382  +
    for crate::error::ContentTypeParametersError
         383  +
{
         384  +
    fn from(
         385  +
        variant: crate::error::InternalServerError,
         386  +
    ) -> crate::error::ContentTypeParametersError {
         387  +
        Self::InternalServerError(variant)
         388  +
    }
         389  +
}
         390  +
         391  +
impl ::std::convert::From<::pyo3::PyErr> for crate::error::ContentTypeParametersError {
         392  +
    fn from(variant: ::pyo3::PyErr) -> crate::error::ContentTypeParametersError {
         393  +
        ::pyo3::Python::with_gil(|py| {
         394  +
            let error = variant.value(py);
         395  +
         396  +
            crate::error::InternalServerError {
         397  +
                message: error.to_string(),
         398  +
            }
         399  +
            .into()
         400  +
        })
         401  +
    }
         402  +
}
         403  +
  348    404   
/// Error type for the `PutWithContentEncoding` operation.
  349    405   
/// Each variant represents an error that can occur for the `PutWithContentEncoding` operation.
  350    406   
#[derive(::std::fmt::Debug)]
  351    407   
pub enum PutWithContentEncodingError {
  352    408   
    #[allow(missing_docs)] // documentation missing in model
  353    409   
    InternalServerError(crate::error::InternalServerError),
  354    410   
}
  355    411   
impl ::std::fmt::Display for PutWithContentEncodingError {
  356    412   
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  357    413   
        match &self {

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/src/input.rs

@@ -163,163 +222,277 @@
  183    183   
impl crate::constrained::Constrained for crate::input::OperationWithDefaultsInput {
  184    184   
    type Unconstrained = crate::input::operation_with_defaults_input_internal::Builder;
  185    185   
}
  186    186   
impl OperationWithDefaultsInput {
  187    187   
    /// Creates a new builder-style object to manufacture [`OperationWithDefaultsInput`](crate::input::OperationWithDefaultsInput).
  188    188   
    pub fn builder() -> crate::input::operation_with_defaults_input::Builder {
  189    189   
        crate::input::operation_with_defaults_input::Builder::default()
  190    190   
    }
  191    191   
}
  192    192   
         193  +
#[::pyo3::pyclass]
         194  +
/// :param value typing.Optional\[int\]:
         195  +
/// :rtype None:
         196  +
#[allow(missing_docs)] // documentation missing in model
         197  +
#[derive(
         198  +
    ::std::clone::Clone, ::std::cmp::Eq, ::std::cmp::PartialEq, ::std::fmt::Debug, ::std::hash::Hash,
         199  +
)]
         200  +
pub struct ContentTypeParametersInput {
         201  +
    #[pyo3(get, set)]
         202  +
    /// :type typing.Optional\[int\]:
         203  +
    #[allow(missing_docs)] // documentation missing in model
         204  +
    pub value: ::std::option::Option<i32>,
         205  +
}
         206  +
impl ContentTypeParametersInput {
         207  +
    #[allow(missing_docs)] // documentation missing in model
         208  +
    pub fn value(&self) -> ::std::option::Option<i32> {
         209  +
        self.value
         210  +
    }
         211  +
}
         212  +
#[allow(clippy::new_without_default)]
         213  +
#[allow(clippy::too_many_arguments)]
         214  +
#[::pyo3::pymethods]
         215  +
impl ContentTypeParametersInput {
         216  +
    #[new]
         217  +
    pub fn new(value: ::std::option::Option<i32>) -> Self {
         218  +
        Self { value }
         219  +
    }
         220  +
    fn __repr__(&self) -> String {
         221  +
        format!("{self:?}")
         222  +
    }
         223  +
    fn __str__(&self) -> String {
         224  +
        format!("{self:?}")
         225  +
    }
         226  +
}
         227  +
impl<'source> ::pyo3::FromPyObject<'source> for std::boxed::Box<ContentTypeParametersInput> {
         228  +
    fn extract(ob: &'source ::pyo3::PyAny) -> ::pyo3::PyResult<Self> {
         229  +
        ob.extract::<ContentTypeParametersInput>().map(Box::new)
         230  +
    }
         231  +
}
         232  +
         233  +
impl ::pyo3::IntoPy<::pyo3::PyObject> for std::boxed::Box<ContentTypeParametersInput> {
         234  +
    fn into_py(self, py: ::pyo3::Python<'_>) -> ::pyo3::PyObject {
         235  +
        (*self).into_py(py)
         236  +
    }
         237  +
}
         238  +
impl crate::constrained::Constrained for crate::input::ContentTypeParametersInput {
         239  +
    type Unconstrained = crate::input::content_type_parameters_input_internal::Builder;
         240  +
}
         241  +
impl ContentTypeParametersInput {
         242  +
    /// Creates a new builder-style object to manufacture [`ContentTypeParametersInput`](crate::input::ContentTypeParametersInput).
         243  +
    pub fn builder() -> crate::input::content_type_parameters_input::Builder {
         244  +
        crate::input::content_type_parameters_input::Builder::default()
         245  +
    }
         246  +
}
         247  +
  193    248   
#[::pyo3::pyclass]
  194    249   
/// :param encoding typing.Optional\[str\]:
  195    250   
/// :param data typing.Optional\[str\]:
  196    251   
/// :rtype None:
  197    252   
#[allow(missing_docs)] // documentation missing in model
  198    253   
#[derive(
  199    254   
    ::std::clone::Clone, ::std::cmp::Eq, ::std::cmp::PartialEq, ::std::fmt::Debug, ::std::hash::Hash,
  200    255   
)]
  201    256   
pub struct PutWithContentEncodingInput {
  202    257   
    #[pyo3(get, set)]
@@ -1101,1156 +1160,1275 @@
 1121   1176   
                client_optional_defaults: self.client_optional_defaults,
 1122   1177   
                top_level_default: self.top_level_default.unwrap_or_else(
 1123   1178   
                    #[allow(clippy::redundant_closure)]
 1124   1179   
                    || String::from("hi"),
 1125   1180   
                ),
 1126   1181   
                other_top_level_default: self.other_top_level_default.unwrap_or(0i32),
 1127   1182   
            }
 1128   1183   
        }
 1129   1184   
    }
 1130   1185   
}
        1186  +
/// See [`ContentTypeParametersInput`](crate::input::ContentTypeParametersInput).
        1187  +
///
        1188  +
pub(crate) mod content_type_parameters_input_internal {
        1189  +
        1190  +
    impl ::std::convert::From<Builder> for crate::input::ContentTypeParametersInput {
        1191  +
        fn from(builder: Builder) -> Self {
        1192  +
            builder.build()
        1193  +
        }
        1194  +
    }
        1195  +
    /// A builder for [`ContentTypeParametersInput`](crate::input::ContentTypeParametersInput).
        1196  +
    #[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug)]
        1197  +
    pub(crate) struct Builder {
        1198  +
        pub(crate) value: ::std::option::Option<i32>,
        1199  +
    }
        1200  +
    impl Builder {
        1201  +
        #[allow(missing_docs)] // documentation missing in model
        1202  +
        pub(crate) fn set_value(mut self, input: Option<impl ::std::convert::Into<i32>>) -> Self {
        1203  +
            self.value = input.map(|v| v.into());
        1204  +
            self
        1205  +
        }
        1206  +
        /// Consumes the builder and constructs a [`ContentTypeParametersInput`](crate::input::ContentTypeParametersInput).
        1207  +
        pub fn build(self) -> crate::input::ContentTypeParametersInput {
        1208  +
            self.build_enforcing_all_constraints()
        1209  +
        }
        1210  +
        fn build_enforcing_all_constraints(self) -> crate::input::ContentTypeParametersInput {
        1211  +
            crate::input::ContentTypeParametersInput { value: self.value }
        1212  +
        }
        1213  +
    }
        1214  +
}
        1215  +
/// See [`ContentTypeParametersInput`](crate::input::ContentTypeParametersInput).
        1216  +
///
        1217  +
pub mod content_type_parameters_input {
        1218  +
        1219  +
    impl ::std::convert::From<Builder> for crate::input::ContentTypeParametersInput {
        1220  +
        fn from(builder: Builder) -> Self {
        1221  +
            builder.build()
        1222  +
        }
        1223  +
    }
        1224  +
    /// A builder for [`ContentTypeParametersInput`](crate::input::ContentTypeParametersInput).
        1225  +
    #[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug)]
        1226  +
    pub struct Builder {
        1227  +
        pub(crate) value: ::std::option::Option<i32>,
        1228  +
    }
        1229  +
    impl Builder {
        1230  +
        #[allow(missing_docs)] // documentation missing in model
        1231  +
        pub fn value(mut self, input: ::std::option::Option<i32>) -> Self {
        1232  +
            self.value = input;
        1233  +
            self
        1234  +
        }
        1235  +
        /// Consumes the builder and constructs a [`ContentTypeParametersInput`](crate::input::ContentTypeParametersInput).
        1236  +
        pub fn build(self) -> crate::input::ContentTypeParametersInput {
        1237  +
            self.build_enforcing_required_and_enum_traits()
        1238  +
        }
        1239  +
        fn build_enforcing_required_and_enum_traits(
        1240  +
            self,
        1241  +
        ) -> crate::input::ContentTypeParametersInput {
        1242  +
            crate::input::ContentTypeParametersInput { value: self.value }
        1243  +
        }
        1244  +
    }
        1245  +
}
 1131   1246   
/// See [`PutWithContentEncodingInput`](crate::input::PutWithContentEncodingInput).
 1132   1247   
///
 1133   1248   
pub(crate) mod put_with_content_encoding_input_internal {
 1134   1249   
 1135   1250   
    impl ::std::convert::From<Builder> for crate::input::PutWithContentEncodingInput {
 1136   1251   
        fn from(builder: Builder) -> Self {
 1137   1252   
            builder.build()
 1138   1253   
        }
 1139   1254   
    }
 1140   1255   
    /// A builder for [`PutWithContentEncodingInput`](crate::input::PutWithContentEncodingInput).

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/src/lib.rs

@@ -130,130 +218,223 @@
  150    150   
//! # Example
  151    151   
//!
  152    152   
//! ```rust,no_run
  153    153   
//! # use std::net::SocketAddr;
  154    154   
//! use json_rpc10::{JsonRpc10, JsonRpc10Config};
  155    155   
//!
  156    156   
//! #[::tokio::main]
  157    157   
//! pub async fn main() {
  158    158   
//!    let config = JsonRpc10Config::builder().build();
  159    159   
//!    let app = JsonRpc10::builder(config)
         160  +
//!        .content_type_parameters(content_type_parameters)
  160    161   
//!        .empty_input_and_empty_output(empty_input_and_empty_output)
  161    162   
//!        .endpoint_operation(endpoint_operation)
  162    163   
//!        .endpoint_with_host_label_operation(endpoint_with_host_label_operation)
  163    164   
//!        .greeting_with_errors(greeting_with_errors)
  164    165   
//!        .host_with_path_operation(host_with_path_operation)
  165    166   
//!        .json_unions(json_unions)
  166    167   
//!        .no_input_and_no_output(no_input_and_no_output)
  167    168   
//!        .no_input_and_output(no_input_and_output)
  168    169   
//!        .operation_with_defaults(operation_with_defaults)
  169    170   
//!        .operation_with_nested_structure(operation_with_nested_structure)
  170    171   
//!        .operation_with_required_members(operation_with_required_members)
  171    172   
//!        .put_with_content_encoding(put_with_content_encoding)
  172    173   
//!        .simple_scalar_properties(simple_scalar_properties)
  173    174   
//!        .build()
  174    175   
//!        .expect("failed to build an instance of JsonRpc10");
  175    176   
//!
  176    177   
//!    let bind: SocketAddr = "127.0.0.1:6969".parse()
  177    178   
//!        .expect("unable to parse the server bind address and port");
  178    179   
//!    let server = ::hyper::Server::bind(&bind).serve(app.into_make_service());
  179    180   
//!    # let server = async { Ok::<_, ()>(()) };
  180    181   
//!
  181    182   
//!    // Run your service!
  182    183   
//!    if let Err(err) = server.await {
  183    184   
//!        eprintln!("server error: {:?}", err);
  184    185   
//!    }
  185    186   
//! }
  186    187   
//!
  187    188   
//! use json_rpc10::{input, output, error};
  188    189   
//!
         190  +
//! async fn content_type_parameters(input: input::ContentTypeParametersInput) -> Result<output::ContentTypeParametersOutput, error::ContentTypeParametersError> {
         191  +
//!     todo!()
         192  +
//! }
         193  +
//!
  189    194   
//! async fn empty_input_and_empty_output(input: input::EmptyInputAndEmptyOutputInput) -> Result<output::EmptyInputAndEmptyOutputOutput, error::EmptyInputAndEmptyOutputError> {
  190    195   
//!     todo!()
  191    196   
//! }
  192    197   
//!
  193    198   
//! async fn endpoint_operation(input: input::EndpointOperationInput) -> Result<output::EndpointOperationOutput, error::EndpointOperationError> {
  194    199   
//!     todo!()
  195    200   
//! }
  196    201   
//!
  197    202   
//! async fn endpoint_with_host_label_operation(input: input::EndpointWithHostLabelOperationInput) -> Result<output::EndpointWithHostLabelOperationOutput, error::EndpointWithHostLabelOperationError> {
  198    203   
//!     todo!()

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/src/operation.rs

@@ -281,281 +340,443 @@
  301    301   
                response
  302    302   
            },
  303    303   
            Err(e) => {
  304    304   
                ::tracing::error!(error = %e, "failed to serialize response");
  305    305   
                ::aws_smithy_http_server::response::IntoResponse::<::aws_smithy_http_server::protocol::aws_json_10::AwsJson1_0>::into_response(::aws_smithy_http_server::protocol::aws_json::runtime_error::RuntimeError::from(e))
  306    306   
            }
  307    307   
        }
  308    308   
    }
  309    309   
}
  310    310   
         311  +
static CONTENT_TYPE_CONTENTTYPEPARAMETERS: ::once_cell::sync::Lazy<::mime::Mime> =
         312  +
    ::once_cell::sync::Lazy::new(|| {
         313  +
        "application/x-amz-json-1.0"
         314  +
            .parse::<::mime::Mime>()
         315  +
            .expect("BUG: MIME parsing failed, content_type is not valid")
         316  +
    });
         317  +
::pin_project_lite::pin_project! {
         318  +
    /// A [`Future`](std::future::Future) aggregating the body bytes of a [`Request`] and constructing the
         319  +
    /// [`ContentTypeParametersInput`](crate::input::ContentTypeParametersInput) using modelled bindings.
         320  +
    pub struct ContentTypeParametersInputFuture {
         321  +
        inner: std::pin::Pin<Box<dyn std::future::Future<Output = Result<crate::input::ContentTypeParametersInput, ::aws_smithy_http_server::protocol::aws_json::runtime_error::RuntimeError>> + Send>>
         322  +
    }
         323  +
}
         324  +
         325  +
impl std::future::Future for ContentTypeParametersInputFuture {
         326  +
    type Output = Result<
         327  +
        crate::input::ContentTypeParametersInput,
         328  +
        ::aws_smithy_http_server::protocol::aws_json::runtime_error::RuntimeError,
         329  +
    >;
         330  +
         331  +
    fn poll(
         332  +
        self: std::pin::Pin<&mut Self>,
         333  +
        cx: &mut std::task::Context<'_>,
         334  +
    ) -> std::task::Poll<Self::Output> {
         335  +
        let this = self.project();
         336  +
        this.inner.as_mut().poll(cx)
         337  +
    }
         338  +
}
         339  +
         340  +
impl<B>
         341  +
    ::aws_smithy_http_server::request::FromRequest<
         342  +
        ::aws_smithy_http_server::protocol::aws_json_10::AwsJson1_0,
         343  +
        B,
         344  +
    > for crate::input::ContentTypeParametersInput
         345  +
where
         346  +
    B: ::aws_smithy_http_server::body::HttpBody + Send,
         347  +
    B: 'static,
         348  +
         349  +
    B::Data: Send,
         350  +
    ::aws_smithy_http_server::protocol::aws_json::rejection::RequestRejection:
         351  +
        From<<B as ::aws_smithy_http_server::body::HttpBody>::Error>,
         352  +
{
         353  +
    type Rejection = ::aws_smithy_http_server::protocol::aws_json::runtime_error::RuntimeError;
         354  +
    type Future = ContentTypeParametersInputFuture;
         355  +
         356  +
    fn from_request(request: ::http::Request<B>) -> Self::Future {
         357  +
        let fut = async move {
         358  +
            if !::aws_smithy_http_server::protocol::accept_header_classifier(
         359  +
                request.headers(),
         360  +
                &CONTENT_TYPE_CONTENTTYPEPARAMETERS,
         361  +
            ) {
         362  +
                return Err(::aws_smithy_http_server::protocol::aws_json::rejection::RequestRejection::NotAcceptable);
         363  +
            }
         364  +
            crate::protocol_serde::shape_content_type_parameters::de_content_type_parameters_http_request(request)
         365  +
                            .await
         366  +
                            .map_err(Into::into)
         367  +
        };
         368  +
        use ::futures_util::future::TryFutureExt;
         369  +
        let fut = fut.map_err(
         370  +
            |e: ::aws_smithy_http_server::protocol::aws_json::rejection::RequestRejection| {
         371  +
                ::tracing::debug!(error = %e, "failed to deserialize request");
         372  +
                ::aws_smithy_http_server::protocol::aws_json::runtime_error::RuntimeError::from(e)
         373  +
            },
         374  +
        );
         375  +
        ContentTypeParametersInputFuture {
         376  +
            inner: Box::pin(fut),
         377  +
        }
         378  +
    }
         379  +
}
         380  +
impl
         381  +
    ::aws_smithy_http_server::response::IntoResponse<
         382  +
        ::aws_smithy_http_server::protocol::aws_json_10::AwsJson1_0,
         383  +
    > for crate::output::ContentTypeParametersOutput
         384  +
{
         385  +
    fn into_response(self) -> ::aws_smithy_http_server::response::Response {
         386  +
        match crate::protocol_serde::shape_content_type_parameters::ser_content_type_parameters_http_response(self) {
         387  +
                        Ok(response) => response,
         388  +
                        Err(e) => {
         389  +
                            ::tracing::error!(error = %e, "failed to serialize response");
         390  +
                            ::aws_smithy_http_server::response::IntoResponse::<::aws_smithy_http_server::protocol::aws_json_10::AwsJson1_0>::into_response(::aws_smithy_http_server::protocol::aws_json::runtime_error::RuntimeError::from(e))
         391  +
                        }
         392  +
                    }
         393  +
    }
         394  +
}
         395  +
impl
         396  +
    ::aws_smithy_http_server::response::IntoResponse<
         397  +
        ::aws_smithy_http_server::protocol::aws_json_10::AwsJson1_0,
         398  +
    > for crate::error::ContentTypeParametersError
         399  +
{
         400  +
    fn into_response(self) -> ::aws_smithy_http_server::response::Response {
         401  +
        match crate::protocol_serde::shape_content_type_parameters::ser_content_type_parameters_http_error(&self) {
         402  +
            Ok(mut response) => {
         403  +
                response.extensions_mut().insert(::aws_smithy_http_server::extension::ModeledErrorExtension::new(self.name()));
         404  +
                response
         405  +
            },
         406  +
            Err(e) => {
         407  +
                ::tracing::error!(error = %e, "failed to serialize response");
         408  +
                ::aws_smithy_http_server::response::IntoResponse::<::aws_smithy_http_server::protocol::aws_json_10::AwsJson1_0>::into_response(::aws_smithy_http_server::protocol::aws_json::runtime_error::RuntimeError::from(e))
         409  +
            }
         410  +
        }
         411  +
    }
         412  +
}
         413  +
  311    414   
static CONTENT_TYPE_PUTWITHCONTENTENCODING: ::once_cell::sync::Lazy<::mime::Mime> =
  312    415   
    ::once_cell::sync::Lazy::new(|| {
  313    416   
        "application/x-amz-json-1.0"
  314    417   
            .parse::<::mime::Mime>()
  315    418   
            .expect("BUG: MIME parsing failed, content_type is not valid")
  316    419   
    });
  317    420   
::pin_project_lite::pin_project! {
  318    421   
    /// A [`Future`](std::future::Future) aggregating the body bytes of a [`Request`] and constructing the
  319    422   
    /// [`PutWithContentEncodingInput`](crate::input::PutWithContentEncodingInput) using modelled bindings.
  320    423   
    pub struct PutWithContentEncodingInputFuture {

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/src/operation_shape.rs

@@ -63,63 +122,151 @@
   83     83   
   84     84   
    fn request_fmt() -> Self::RequestFmt {
   85     85   
        ::aws_smithy_http_server::instrumentation::sensitivity::RequestFmt::new()
   86     86   
    }
   87     87   
   88     88   
    fn response_fmt() -> Self::ResponseFmt {
   89     89   
        ::aws_smithy_http_server::instrumentation::sensitivity::ResponseFmt::new()
   90     90   
    }
   91     91   
}
   92     92   
          93  +
/// The example tests how servers must support requests containing a `Content-Type` header with parameters.
          94  +
pub struct ContentTypeParameters;
          95  +
          96  +
impl ::aws_smithy_http_server::operation::OperationShape for ContentTypeParameters {
          97  +
    const ID: ::aws_smithy_http_server::shape_id::ShapeId =
          98  +
        ::aws_smithy_http_server::shape_id::ShapeId::new(
          99  +
            "aws.protocoltests.json10#ContentTypeParameters",
         100  +
            "aws.protocoltests.json10",
         101  +
            "ContentTypeParameters",
         102  +
        );
         103  +
         104  +
    type Input = crate::input::ContentTypeParametersInput;
         105  +
    type Output = crate::output::ContentTypeParametersOutput;
         106  +
    type Error = crate::error::ContentTypeParametersError;
         107  +
}
         108  +
         109  +
impl ::aws_smithy_http_server::instrumentation::sensitivity::Sensitivity for ContentTypeParameters {
         110  +
    type RequestFmt = ::aws_smithy_http_server::instrumentation::sensitivity::DefaultRequestFmt;
         111  +
    type ResponseFmt = ::aws_smithy_http_server::instrumentation::sensitivity::DefaultResponseFmt;
         112  +
         113  +
    fn request_fmt() -> Self::RequestFmt {
         114  +
        ::aws_smithy_http_server::instrumentation::sensitivity::RequestFmt::new()
         115  +
    }
         116  +
         117  +
    fn response_fmt() -> Self::ResponseFmt {
         118  +
        ::aws_smithy_http_server::instrumentation::sensitivity::ResponseFmt::new()
         119  +
    }
         120  +
}
         121  +
   93    122   
#[allow(missing_docs)] // documentation missing in model
   94    123   
pub struct PutWithContentEncoding;
   95    124   
   96    125   
impl ::aws_smithy_http_server::operation::OperationShape for PutWithContentEncoding {
   97    126   
    const ID: ::aws_smithy_http_server::shape_id::ShapeId =
   98    127   
        ::aws_smithy_http_server::shape_id::ShapeId::new(
   99    128   
            "aws.protocoltests.json10#PutWithContentEncoding",
  100    129   
            "aws.protocoltests.json10",
  101    130   
            "PutWithContentEncoding",
  102    131   
        );

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/src/output.rs

@@ -597,597 +656,696 @@
  617    617   
        (*self).into_py(py)
  618    618   
    }
  619    619   
}
  620    620   
impl OperationWithDefaultsOutput {
  621    621   
    /// Creates a new builder-style object to manufacture [`OperationWithDefaultsOutput`](crate::output::OperationWithDefaultsOutput).
  622    622   
    pub fn builder() -> crate::output::operation_with_defaults_output::Builder {
  623    623   
        crate::output::operation_with_defaults_output::Builder::default()
  624    624   
    }
  625    625   
}
  626    626   
         627  +
#[::pyo3::pyclass]
         628  +
/// :rtype None:
         629  +
#[allow(missing_docs)] // documentation missing in model
         630  +
#[derive(
         631  +
    ::std::clone::Clone, ::std::cmp::Eq, ::std::cmp::PartialEq, ::std::fmt::Debug, ::std::hash::Hash,
         632  +
)]
         633  +
pub struct ContentTypeParametersOutput {}
         634  +
#[allow(clippy::new_without_default)]
         635  +
#[allow(clippy::too_many_arguments)]
         636  +
#[::pyo3::pymethods]
         637  +
impl ContentTypeParametersOutput {
         638  +
    #[new]
         639  +
    pub fn new() -> Self {
         640  +
        Self {}
         641  +
    }
         642  +
    fn __repr__(&self) -> String {
         643  +
        format!("{self:?}")
         644  +
    }
         645  +
    fn __str__(&self) -> String {
         646  +
        format!("{self:?}")
         647  +
    }
         648  +
}
         649  +
impl<'source> ::pyo3::FromPyObject<'source> for std::boxed::Box<ContentTypeParametersOutput> {
         650  +
    fn extract(ob: &'source ::pyo3::PyAny) -> ::pyo3::PyResult<Self> {
         651  +
        ob.extract::<ContentTypeParametersOutput>().map(Box::new)
         652  +
    }
         653  +
}
         654  +
         655  +
impl ::pyo3::IntoPy<::pyo3::PyObject> for std::boxed::Box<ContentTypeParametersOutput> {
         656  +
    fn into_py(self, py: ::pyo3::Python<'_>) -> ::pyo3::PyObject {
         657  +
        (*self).into_py(py)
         658  +
    }
         659  +
}
         660  +
impl ContentTypeParametersOutput {
         661  +
    /// Creates a new builder-style object to manufacture [`ContentTypeParametersOutput`](crate::output::ContentTypeParametersOutput).
         662  +
    pub fn builder() -> crate::output::content_type_parameters_output::Builder {
         663  +
        crate::output::content_type_parameters_output::Builder::default()
         664  +
    }
         665  +
}
         666  +
  627    667   
#[::pyo3::pyclass]
  628    668   
/// :rtype None:
  629    669   
#[allow(missing_docs)] // documentation missing in model
  630    670   
#[derive(
  631    671   
    ::std::clone::Clone, ::std::cmp::Eq, ::std::cmp::PartialEq, ::std::fmt::Debug, ::std::hash::Hash,
  632    672   
)]
  633    673   
pub struct PutWithContentEncodingOutput {}
  634    674   
#[allow(clippy::new_without_default)]
  635    675   
#[allow(clippy::too_many_arguments)]
  636    676   
#[::pyo3::pymethods]
@@ -1628,1668 +1687,1751 @@
 1648   1688   
                zero_byte: self.zero_byte.unwrap_or(0i8),
 1649   1689   
                zero_short: self.zero_short.unwrap_or(0i16),
 1650   1690   
                zero_integer: self.zero_integer.unwrap_or(0i32),
 1651   1691   
                zero_long: self.zero_long.unwrap_or(0i64),
 1652   1692   
                zero_float: self.zero_float.unwrap_or(0.0f32),
 1653   1693   
                zero_double: self.zero_double.unwrap_or(0.0f64),
 1654   1694   
            }
 1655   1695   
        }
 1656   1696   
    }
 1657   1697   
}
        1698  +
/// See [`ContentTypeParametersOutput`](crate::output::ContentTypeParametersOutput).
        1699  +
///
        1700  +
pub mod content_type_parameters_output {
        1701  +
        1702  +
    impl ::std::convert::From<Builder> for crate::output::ContentTypeParametersOutput {
        1703  +
        fn from(builder: Builder) -> Self {
        1704  +
            builder.build()
        1705  +
        }
        1706  +
    }
        1707  +
    /// A builder for [`ContentTypeParametersOutput`](crate::output::ContentTypeParametersOutput).
        1708  +
    #[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug)]
        1709  +
    pub struct Builder {}
        1710  +
    impl Builder {
        1711  +
        /// Consumes the builder and constructs a [`ContentTypeParametersOutput`](crate::output::ContentTypeParametersOutput).
        1712  +
        pub fn build(self) -> crate::output::ContentTypeParametersOutput {
        1713  +
            self.build_enforcing_required_and_enum_traits()
        1714  +
        }
        1715  +
        fn build_enforcing_required_and_enum_traits(
        1716  +
            self,
        1717  +
        ) -> crate::output::ContentTypeParametersOutput {
        1718  +
            crate::output::ContentTypeParametersOutput {}
        1719  +
        }
        1720  +
    }
        1721  +
}
 1658   1722   
/// See [`PutWithContentEncodingOutput`](crate::output::PutWithContentEncodingOutput).
 1659   1723   
///
 1660   1724   
pub mod put_with_content_encoding_output {
 1661   1725   
 1662   1726   
    impl ::std::convert::From<Builder> for crate::output::PutWithContentEncodingOutput {
 1663   1727   
        fn from(builder: Builder) -> Self {
 1664   1728   
            builder.build()
 1665   1729   
        }
 1666   1730   
    }
 1667   1731   
    /// A builder for [`PutWithContentEncodingOutput`](crate::output::PutWithContentEncodingOutput).

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/src/protocol_serde.rs

@@ -1,1 +69,73 @@
    1      1   
// Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
           2  +
pub(crate) mod shape_content_type_parameters;
           3  +
    2      4   
pub(crate) mod shape_empty_input_and_empty_output;
    3      5   
    4      6   
pub(crate) mod shape_endpoint_operation;
    5      7   
    6      8   
pub(crate) mod shape_endpoint_with_host_label_operation;
    7      9   
    8     10   
pub(crate) mod shape_greeting_with_errors;
    9     11   
   10     12   
pub(crate) mod shape_host_with_path_operation;
   11     13   
   12     14   
pub(crate) mod shape_json_unions;
   13     15   
   14     16   
pub(crate) mod shape_no_input_and_no_output;
   15     17   
   16     18   
pub(crate) mod shape_no_input_and_output;
   17     19   
   18     20   
pub(crate) mod shape_operation_with_defaults;
   19     21   
   20     22   
pub(crate) mod shape_operation_with_nested_structure;
   21     23   
   22     24   
pub(crate) mod shape_operation_with_required_members;
   23     25   
   24     26   
pub(crate) mod shape_put_with_content_encoding;
   25     27   
   26     28   
pub(crate) mod shape_simple_scalar_properties;
   27     29   
   28     30   
pub(crate) mod shape_complex_error;
   29     31   
   30         -
pub(crate) mod shape_empty_input_and_empty_output_output;
   31         -
   32     32   
pub(crate) fn or_empty_doc(data: &[u8]) -> &[u8] {
   33     33   
    if data.is_empty() {
   34     34   
        b"{}"
   35     35   
    } else {
   36     36   
        data
   37     37   
    }
   38     38   
}
   39     39   
          40  +
pub(crate) mod shape_content_type_parameters_output;
          41  +
          42  +
pub(crate) mod shape_empty_input_and_empty_output_output;
          43  +
   40     44   
pub(crate) mod shape_foo_error;
   41     45   
   42     46   
pub(crate) mod shape_greeting_with_errors_output;
   43     47   
   44     48   
pub(crate) mod shape_internal_server_error;
   45     49   
   46     50   
pub(crate) mod shape_invalid_greeting;
   47     51   
   48     52   
pub(crate) mod shape_json_unions_output;
   49     53   

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/src/protocol_serde/shape_content_type_parameters.rs

@@ -0,1 +0,148 @@
           1  +
// Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
           2  +
#[allow(clippy::unnecessary_wraps)]
           3  +
pub async fn de_content_type_parameters_http_request<B>(
           4  +
    #[allow(unused_variables)] request: ::http::Request<B>,
           5  +
) -> std::result::Result<
           6  +
    crate::input::ContentTypeParametersInput,
           7  +
    ::aws_smithy_http_server::protocol::aws_json::rejection::RequestRejection,
           8  +
>
           9  +
where
          10  +
    B: ::aws_smithy_http_server::body::HttpBody + Send,
          11  +
    B::Data: Send,
          12  +
    ::aws_smithy_http_server::protocol::aws_json::rejection::RequestRejection:
          13  +
        From<<B as ::aws_smithy_http_server::body::HttpBody>::Error>,
          14  +
{
          15  +
    Ok({
          16  +
        #[allow(unused_mut)]
          17  +
        let mut input = crate::input::content_type_parameters_input_internal::Builder::default();
          18  +
        #[allow(unused_variables)]
          19  +
        let ::aws_smithy_runtime_api::http::RequestParts {
          20  +
            uri, headers, body, ..
          21  +
        } = ::aws_smithy_runtime_api::http::Request::try_from(request)?.into_parts();
          22  +
        let bytes = ::hyper::body::to_bytes(body).await?;
          23  +
        if !bytes.is_empty() {
          24  +
            ::aws_smithy_http_server::protocol::content_type_header_classifier_smithy(
          25  +
                &headers,
          26  +
                Some("application/x-amz-json-1.0"),
          27  +
            )?;
          28  +
            input =
          29  +
                crate::protocol_serde::shape_content_type_parameters::de_content_type_parameters(
          30  +
                    bytes.as_ref(),
          31  +
                    input,
          32  +
                )?;
          33  +
        }
          34  +
        input.build()
          35  +
    })
          36  +
}
          37  +
          38  +
#[allow(clippy::unnecessary_wraps)]
          39  +
pub fn ser_content_type_parameters_http_response(
          40  +
    #[allow(unused_variables)] output: crate::output::ContentTypeParametersOutput,
          41  +
) -> std::result::Result<
          42  +
    ::aws_smithy_http_server::response::Response,
          43  +
    ::aws_smithy_http_server::protocol::aws_json::rejection::ResponseRejection,
          44  +
> {
          45  +
    Ok({
          46  +
        #[allow(unused_mut)]
          47  +
        let mut builder = ::http::Response::builder();
          48  +
        builder = ::aws_smithy_http::header::set_response_header_if_absent(
          49  +
            builder,
          50  +
            ::http::header::CONTENT_TYPE,
          51  +
            "application/x-amz-json-1.0",
          52  +
        );
          53  +
        let http_status: u16 = 200;
          54  +
        builder = builder.status(http_status);
          55  +
        let payload =
          56  +
            crate::protocol_serde::shape_content_type_parameters_output::ser_content_type_parameters_output_output_output(&output)?
          57  +
        ;
          58  +
        let content_length = payload.len();
          59  +
        builder = ::aws_smithy_http::header::set_response_header_if_absent(
          60  +
            builder,
          61  +
            ::http::header::CONTENT_LENGTH,
          62  +
            content_length,
          63  +
        );
          64  +
        let body = ::aws_smithy_http_server::body::to_boxed(payload);
          65  +
        builder.body(body)?
          66  +
    })
          67  +
}
          68  +
          69  +
#[allow(clippy::unnecessary_wraps)]
          70  +
pub fn ser_content_type_parameters_http_error(
          71  +
    error: &crate::error::ContentTypeParametersError,
          72  +
) -> std::result::Result<
          73  +
    ::aws_smithy_http_server::response::Response,
          74  +
    ::aws_smithy_http_server::protocol::aws_json::rejection::ResponseRejection,
          75  +
> {
          76  +
    Ok({
          77  +
        match error {
          78  +
            crate::error::ContentTypeParametersError::InternalServerError(output) => {
          79  +
                let payload = crate::protocol_serde::shape_internal_server_error::ser_internal_server_error_error(output)?;
          80  +
                #[allow(unused_mut)]
          81  +
                let mut builder = ::http::Response::builder();
          82  +
                builder = ::aws_smithy_http::header::set_response_header_if_absent(
          83  +
                    builder,
          84  +
                    ::http::header::CONTENT_TYPE,
          85  +
                    "application/x-amz-json-1.0",
          86  +
                );
          87  +
                let content_length = payload.len();
          88  +
                builder = ::aws_smithy_http::header::set_response_header_if_absent(
          89  +
                    builder,
          90  +
                    ::http::header::CONTENT_LENGTH,
          91  +
                    content_length,
          92  +
                );
          93  +
                builder
          94  +
                    .status(500)
          95  +
                    .body(::aws_smithy_http_server::body::to_boxed(payload))?
          96  +
            }
          97  +
        }
          98  +
    })
          99  +
}
         100  +
         101  +
pub(crate) fn de_content_type_parameters(
         102  +
    value: &[u8],
         103  +
    mut builder: crate::input::content_type_parameters_input_internal::Builder,
         104  +
) -> Result<
         105  +
    crate::input::content_type_parameters_input_internal::Builder,
         106  +
    ::aws_smithy_json::deserialize::error::DeserializeError,
         107  +
> {
         108  +
    let mut tokens_owned =
         109  +
        ::aws_smithy_json::deserialize::json_token_iter(crate::protocol_serde::or_empty_doc(value))
         110  +
            .peekable();
         111  +
    let tokens = &mut tokens_owned;
         112  +
    ::aws_smithy_json::deserialize::token::expect_start_object(tokens.next())?;
         113  +
    loop {
         114  +
        match tokens.next().transpose()? {
         115  +
            Some(::aws_smithy_json::deserialize::Token::EndObject { .. }) => break,
         116  +
            Some(::aws_smithy_json::deserialize::Token::ObjectKey { key, .. }) => {
         117  +
                match key.to_unescaped()?.as_ref() {
         118  +
                    "value" => {
         119  +
                        builder = builder.set_value(
         120  +
                            ::aws_smithy_json::deserialize::token::expect_number_or_null(
         121  +
                                tokens.next(),
         122  +
                            )?
         123  +
                            .map(i32::try_from)
         124  +
                            .transpose()?,
         125  +
                        );
         126  +
                    }
         127  +
                    _ => ::aws_smithy_json::deserialize::token::skip_value(tokens)?,
         128  +
                }
         129  +
            }
         130  +
            other => {
         131  +
                return Err(
         132  +
                    ::aws_smithy_json::deserialize::error::DeserializeError::custom(format!(
         133  +
                        "expected object key or end object, found: {:?}",
         134  +
                        other
         135  +
                    )),
         136  +
                )
         137  +
            }
         138  +
        }
         139  +
    }
         140  +
    if tokens.next().is_some() {
         141  +
        return Err(
         142  +
            ::aws_smithy_json::deserialize::error::DeserializeError::custom(
         143  +
                "found more JSON tokens after completing parsing",
         144  +
            ),
         145  +
        );
         146  +
    }
         147  +
    Ok(builder)
         148  +
}

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/src/protocol_serde/shape_content_type_parameters_output.rs

@@ -0,1 +0,17 @@
           1  +
// Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
           2  +
pub fn ser_content_type_parameters_output_output_output(
           3  +
    value: &crate::output::ContentTypeParametersOutput,
           4  +
) -> Result<String, ::aws_smithy_types::error::operation::SerializationError> {
           5  +
    let mut out = String::new();
           6  +
    let mut object = ::aws_smithy_json::serialize::JsonObjectWriter::new(&mut out);
           7  +
    crate::protocol_serde::shape_content_type_parameters_output::ser_content_type_parameters_output_output(&mut object, value)?;
           8  +
    object.finish();
           9  +
    Ok(out)
          10  +
}
          11  +
          12  +
pub fn ser_content_type_parameters_output_output(
          13  +
    #[allow(unused_variables)] object: &mut ::aws_smithy_json::serialize::JsonObjectWriter,
          14  +
    #[allow(unused_variables)] input: &crate::output::ContentTypeParametersOutput,
          15  +
) -> Result<(), ::aws_smithy_types::error::operation::SerializationError> {
          16  +
    Ok(())
          17  +
}

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/src/python_module_export.rs

@@ -1,1 +53,55 @@
   14     14   
    model.add_class::<crate::model::Farewell>()?;
   15     15   
    input.add_class::<crate::input::OperationWithNestedStructureInput>()?;
   16     16   
    model.add_class::<crate::model::TopLevel>()?;
   17     17   
    output.add_class::<crate::output::OperationWithRequiredMembersOutput>()?;
   18     18   
    input.add_class::<crate::input::OperationWithRequiredMembersInput>()?;
   19     19   
    output.add_class::<crate::output::OperationWithDefaultsOutput>()?;
   20     20   
    model.add_class::<crate::model::TestEnum>()?;
   21     21   
    input.add_class::<crate::input::OperationWithDefaultsInput>()?;
   22     22   
    model.add_class::<crate::model::ClientOptionalDefaults>()?;
   23     23   
    model.add_class::<crate::model::Defaults>()?;
          24  +
    output.add_class::<crate::output::ContentTypeParametersOutput>()?;
          25  +
    input.add_class::<crate::input::ContentTypeParametersInput>()?;
   24     26   
    output.add_class::<crate::output::PutWithContentEncodingOutput>()?;
   25     27   
    input.add_class::<crate::input::PutWithContentEncodingInput>()?;
   26     28   
    output.add_class::<crate::output::HostWithPathOperationOutput>()?;
   27     29   
    input.add_class::<crate::input::HostWithPathOperationInput>()?;
   28     30   
    output.add_class::<crate::output::EndpointWithHostLabelOperationOutput>()?;
   29     31   
    input.add_class::<crate::input::EndpointWithHostLabelOperationInput>()?;
   30     32   
    output.add_class::<crate::output::EndpointOperationOutput>()?;
   31     33   
    input.add_class::<crate::input::EndpointOperationInput>()?;
   32     34   
    output.add_class::<crate::output::JsonUnionsOutput>()?;
   33     35   
    model.add_class::<crate::model::PyUnionMarkerMyUnion>()?;

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/src/python_operation_adaptor.rs

@@ -137,137 +196,251 @@
  157    157   
    result.map_err(|e| {
  158    158   
        let rich_py_err =
  159    159   
            ::aws_smithy_http_server_python::rich_py_err(::pyo3::Python::with_gil(|py| {
  160    160   
                e.clone_ref(py)
  161    161   
            }));
  162    162   
        ::tracing::error!(error = ?rich_py_err, "handler error");
  163    163   
        e.into()
  164    164   
    })
  165    165   
}
  166    166   
         167  +
/// Python handler for operation `ContentTypeParameters`.
         168  +
pub(crate) async fn content_type_parameters(
         169  +
    input: crate::input::ContentTypeParametersInput,
         170  +
    state: ::aws_smithy_http_server::Extension<::aws_smithy_http_server_python::context::PyContext>,
         171  +
    handler: ::aws_smithy_http_server_python::PyHandler,
         172  +
) -> std::result::Result<
         173  +
    crate::output::ContentTypeParametersOutput,
         174  +
    crate::error::ContentTypeParametersError,
         175  +
> {
         176  +
    // Async block used to run the handler and catch any Python error.
         177  +
    let result = if handler.is_coroutine {
         178  +
        ::tracing::trace!(
         179  +
            name = "content_type_parameters",
         180  +
            "executing python handler coroutine"
         181  +
        );
         182  +
        let result = ::pyo3::Python::with_gil(|py| {
         183  +
            let pyhandler: &::pyo3::types::PyFunction = handler.extract(py)?;
         184  +
            let coroutine = if handler.args == 1 {
         185  +
                pyhandler.call1((input,))?
         186  +
            } else {
         187  +
                pyhandler.call1((input, ::pyo3::ToPyObject::to_object(&state.0, py)))?
         188  +
            };
         189  +
            ::pyo3_asyncio::tokio::into_future(coroutine)
         190  +
        })?;
         191  +
        result.await.and_then(|r| {
         192  +
            ::pyo3::Python::with_gil(|py| {
         193  +
                r.extract::<crate::output::ContentTypeParametersOutput>(py)
         194  +
            })
         195  +
        })
         196  +
    } else {
         197  +
        ::tracing::trace!(
         198  +
            name = "content_type_parameters",
         199  +
            "executing python handler function"
         200  +
        );
         201  +
        ::pyo3::Python::with_gil(|py| {
         202  +
            let pyhandler: &::pyo3::types::PyFunction = handler.extract(py)?;
         203  +
            let output = if handler.args == 1 {
         204  +
                pyhandler.call1((input,))?
         205  +
            } else {
         206  +
                pyhandler.call1((input, ::pyo3::ToPyObject::to_object(&state.0, py)))?
         207  +
            };
         208  +
            output.extract::<crate::output::ContentTypeParametersOutput>()
         209  +
        })
         210  +
    };
         211  +
    // Catch and record a Python traceback.
         212  +
    result.map_err(|e| {
         213  +
        let rich_py_err =
         214  +
            ::aws_smithy_http_server_python::rich_py_err(::pyo3::Python::with_gil(|py| {
         215  +
                e.clone_ref(py)
         216  +
            }));
         217  +
        ::tracing::error!(error = ?rich_py_err, "handler error");
         218  +
        e.into()
         219  +
    })
         220  +
}
         221  +
  167    222   
/// Python handler for operation `PutWithContentEncoding`.
  168    223   
pub(crate) async fn put_with_content_encoding(
  169    224   
    input: crate::input::PutWithContentEncodingInput,
  170    225   
    state: ::aws_smithy_http_server::Extension<::aws_smithy_http_server_python::context::PyContext>,
  171    226   
    handler: ::aws_smithy_http_server_python::PyHandler,
  172    227   
) -> std::result::Result<
  173    228   
    crate::output::PutWithContentEncodingOutput,
  174    229   
    crate::error::PutWithContentEncodingError,
  175    230   
> {
  176    231   
    // Async block used to run the handler and catch any Python error.

tmp-codegen-diff/codegen-server-test-python/json_rpc10/rust-server-codegen-python/src/python_server_application.rs

@@ -1,1 +58,64 @@
   19     19   
///     counter: int = 0
   20     20   
///
   21     21   
/// app = App()
   22     22   
/// app.context(Context())
   23     23   
///
   24     24   
/// @app.request_middleware
   25     25   
/// def request_middleware(request: middleware::Request):
   26     26   
///     if request.get_header("x-amzn-id") != "secret":
   27     27   
///         raise middleware.MiddlewareException("Unsupported `x-amz-id` header", 401)
   28     28   
///
          29  +
/// # The example tests how servers must support requests
          30  +
/// # containing a `Content-Type` header with parameters.
          31  +
/// @app.content_type_parameters
          32  +
/// def content_type_parameters(input: input::ContentTypeParametersInput, ctx: Context) -> output::ContentTypeParametersOutput:
          33  +
///     raise NotImplementedError
          34  +
///
   29     35   
/// # The example tests how requests and responses are serialized when there's
   30     36   
/// # no request or response payload because the operation has an empty input
   31     37   
/// # and empty output structure that reuses the same shape. While this should
   32     38   
/// # be rare, code generators must support this.
   33     39   
/// @app.empty_input_and_empty_output
   34     40   
/// def empty_input_and_empty_output(input: input::EmptyInputAndEmptyOutputInput, ctx: Context) -> output::EmptyInputAndEmptyOutputOutput:
   35     41   
///     raise NotImplementedError
   36     42   
///
   37     43   
/// @app.endpoint_operation
   38     44   
/// def endpoint_operation(input: input::EndpointOperationInput, ctx: Context) -> output::EndpointOperationOutput:
@@ -130,136 +189,211 @@
  150    156   
        &mut self,
  151    157   
        event_loop: &::pyo3::PyAny,
  152    158   
    ) -> ::pyo3::PyResult<
  153    159   
        ::tower::util::BoxCloneService<
  154    160   
            ::http::Request<::aws_smithy_http_server::body::Body>,
  155    161   
            ::http::Response<::aws_smithy_http_server::body::BoxBody>,
  156    162   
            std::convert::Infallible,
  157    163   
        >,
  158    164   
    > {
  159    165   
        let builder = crate::service::JsonRpc10::builder_without_plugins();
         166  +
        let content_type_parameters_locals = ::pyo3_asyncio::TaskLocals::new(event_loop);
         167  +
        let handler = self
         168  +
            .handlers
         169  +
            .get("content_type_parameters")
         170  +
            .expect("Python handler for operation `content_type_parameters` not found")
         171  +
            .clone();
         172  +
        let builder = builder.content_type_parameters(move |input, state| {
         173  +
            ::pyo3_asyncio::tokio::scope(
         174  +
                content_type_parameters_locals.clone(),
         175  +
                crate::python_operation_adaptor::content_type_parameters(
         176  +
                    input,
         177  +
                    state,
         178  +
                    handler.clone(),
         179  +
                ),
         180  +
            )
         181  +
        });
  160    182   
        let empty_input_and_empty_output_locals = ::pyo3_asyncio::TaskLocals::new(event_loop);
  161    183   
        let handler = self
  162    184   
            .handlers
  163    185   
            .get("empty_input_and_empty_output")
  164    186   
            .expect("Python handler for operation `empty_input_and_empty_output` not found")
  165    187   
            .clone();
  166    188   
        let builder = builder.empty_input_and_empty_output(move |input, state| {
  167    189   
            ::pyo3_asyncio::tokio::scope(
  168    190   
                empty_input_and_empty_output_locals.clone(),
  169    191   
                crate::python_operation_adaptor::empty_input_and_empty_output(
@@ -430,452 +489,525 @@
  450    472   
        py: pyo3::Python,
  451    473   
        socket: &pyo3::PyCell<::aws_smithy_http_server_python::PySocket>,
  452    474   
        worker_number: isize,
  453    475   
        tls: Option<::aws_smithy_http_server_python::tls::PyTlsConfig>,
  454    476   
    ) -> pyo3::PyResult<()> {
  455    477   
        use ::aws_smithy_http_server_python::PyApp;
  456    478   
        let event_loop = self.configure_python_event_loop(py)?;
  457    479   
        let service = self.build_and_configure_service(py, event_loop)?;
  458    480   
        self.start_hyper_worker(py, socket, event_loop, service, worker_number, tls)
  459    481   
    }
         482  +
    /// Method to register `content_type_parameters` Python implementation inside the handlers map.
         483  +
    /// It can be used as a function decorator in Python.
         484  +
    ///
         485  +
    /// :param func typing.Union\[typing.Callable\[\[json_rpc10.input.ContentTypeParametersInput, Ctx\], typing.Union\[json_rpc10.output.ContentTypeParametersOutput, typing.Awaitable\[json_rpc10.output.ContentTypeParametersOutput\]\]\], typing.Callable\[\[json_rpc10.input.ContentTypeParametersInput\], typing.Union\[json_rpc10.output.ContentTypeParametersOutput, typing.Awaitable\[json_rpc10.output.ContentTypeParametersOutput\]\]\]\]:
         486  +
    /// :rtype None:
         487  +
    #[pyo3(text_signature = "($self, func)")]
         488  +
    pub fn content_type_parameters(
         489  +
        &mut self,
         490  +
        py: ::pyo3::Python,
         491  +
        func: ::pyo3::PyObject,
         492  +
    ) -> ::pyo3::PyResult<()> {
         493  +
        use ::aws_smithy_http_server_python::PyApp;
         494  +
        self.register_operation(py, "content_type_parameters", func)
         495  +
    }
  460    496   
    /// Method to register `empty_input_and_empty_output` Python implementation inside the handlers map.
  461    497   
    /// It can be used as a function decorator in Python.
  462    498   
    ///
  463    499   
    /// :param func typing.Union\[typing.Callable\[\[json_rpc10.input.EmptyInputAndEmptyOutputInput, Ctx\], typing.Union\[json_rpc10.output.EmptyInputAndEmptyOutputOutput, typing.Awaitable\[json_rpc10.output.EmptyInputAndEmptyOutputOutput\]\]\], typing.Callable\[\[json_rpc10.input.EmptyInputAndEmptyOutputInput\], typing.Union\[json_rpc10.output.EmptyInputAndEmptyOutputOutput, typing.Awaitable\[json_rpc10.output.EmptyInputAndEmptyOutputOutput\]\]\]\]:
  464    500   
    /// :rtype None:
  465    501   
    #[pyo3(text_signature = "($self, func)")]
  466    502   
    pub fn empty_input_and_empty_output(
  467    503   
        &mut self,
  468    504   
        py: ::pyo3::Python,
  469    505   
        func: ::pyo3::PyObject,