Do not inline non-primitive type parameters by default

Fixes https://github.com/juhaku/utoipa/issues/1182

[ ] Implement a more comprehensive inlining strategy for generic type parameters
[ ] Fix the tests
[ ] Update the CHANGELOG

@juhaku I attempted to fix the openapi_schemas_resolve_schema_references to add #[schema(inline)] where the reference expects it. But I think the reference is wrong.
Here is the difference:
43c43
<                 "type": "object"
---
>                 "type": "string"
97a98,123
>                 "properties": {
>                   "accounts": {
>                     "items": {
>                       "oneOf": [
>                         {
>                           "type": "null"
>                         },
>                         {
>                           "$ref": "#/components/schemas/Account"
>                         }
>                       ]
>                     },
>                     "type": "array"
>                   },
>                   "foo_bar": {
>                     "$ref": "#/components/schemas/Foobar"
>                   },
>                   "name": {
>                     "type": "string"
>                   }
>                 },
>                 "required": [
>                   "name",
>                   "foo_bar",
>                   "accounts"
>                 ],

I think the reference is wrong:

Element_String.oneOf[1].properties.Many.items.type should be string (just like the One variant), but it is object in the reference.
Element_Yeah.oneOf[1].properties.Many.items.type should be the inlined schema of Yeah, but it is { "type": "object" } in the reference.

Should I fix the reference?

True it is indeed wrong, I definitely would appreciate if you want to take the initiative to enter to the rabbit hole of generics and fix the broken references as well. :laughing: For now I have no idea as of yet that what is causing that misalignment.

But maybe we can just leave it as is. Like without the inline it will now create correct reference. And with inline it does inline the actual type. So I think this is probably something that we want and we can just settle the fact that for now on the generics are not inlined by default? :thinking:

True it is indeed wrong, I definitely would appreciate if you want to take the initiative to enter to the rabbit hole of generics and fix the broken references as well. 😆 For now I have no idea as of yet that what is causing that misalignment.

@juhaku that's the neat part : my PR fixes it AFAIK. But I just wanted your approval before changing the reference JSON.

But maybe we can just leave it as is. Like without the inline it will now create correct reference. And with inline it does inline the actual type. So I think this is probably something that we want and we can just settle the fact that for now on the generics are not inlined by default?

My point exactly. The result with those changes is IMO better and fixes that broken test/reference. So if I just change the reference JSON:

the expected result is correct
the way inlining + generics works is IMHO more sound
but generics are now using refs instead of inlining

But you can't have 2. without 3.
So if that's ok with you I will:

Fix the reference JSON for the broken test.
Update the CHANGELOG

Yes, that is ok for me, thanks for the work :slightly_smiling_face: :+1:

If I check only with schema.is_primitive(), I get the following failed test:
test derive_generic_schema_enum_variants ... FAILED

failures:

---- derive_generic_schema_enum_variants stdout ----
{
  "openapi": "3.1.0",
  "info": {
    "title": "title",
    "version": "version"
  },
  "paths": {},
  "components": {
    "schemas": {
      "BTreeMap": {
        "type": "object",
        "additionalProperties": {
          "type": "string"
        },
        "propertyNames": {
          "type": "string"
        }
      },
      "BTreeSet": {
        "type": "array",
        "items": {
          "type": "integer",
          "format": "int32"
        },
        "uniqueItems": true
      },
      "FooStruct_Option_i32": {
        "type": "object",
        "required": [
          "foo"
        ],
        "properties": {
          "foo": {
            "$ref": "#/components/schemas/Option"
          }
        }
      },
      "FoosEnum": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "ThingNoAliasOption"
            ],
            "properties": {
              "ThingNoAliasOption": {
                "$ref": "#/components/schemas/FooStruct_Option_i32"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "FooEnumThing"
            ],
            "properties": {
              "FooEnumThing": {
                "type": "object",
                "required": [
                  "foo"
                ],
                "properties": {
                  "foo": {
                    "$ref": "#/components/schemas/Vec"
                  }
                }
              }
            }
          },
          {
            "type": "object",
            "required": [
              "FooThingOptionVec"
            ],
            "properties": {
              "FooThingOptionVec": {
                "type": "object",
                "required": [
                  "foo"
                ],
                "properties": {
                  "foo": {
                    "$ref": "#/components/schemas/Option"
                  }
                }
              }
            }
          },
          {
            "type": "object",
            "required": [
              "FooThingLinkedList"
            ],
            "properties": {
              "FooThingLinkedList": {
                "type": "object",
                "required": [
                  "foo"
                ],
                "properties": {
                  "foo": {
                    "$ref": "#/components/schemas/LinkedList"
                  }
                }
              }
            }
          },
          {
            "type": "object",
            "required": [
              "FooThingBTreeMap"
            ],
            "properties": {
              "FooThingBTreeMap": {
                "type": "object",
                "required": [
                  "foo"
                ],
                "properties": {
                  "foo": {
                    "$ref": "#/components/schemas/BTreeMap"
                  }
                }
              }
            }
          },
          {
            "type": "object",
            "required": [
              "FooThingHashMap"
            ],
            "properties": {
              "FooThingHashMap": {
                "type": "object",
                "required": [
                  "foo"
                ],
                "properties": {
                  "foo": {
                    "$ref": "#/components/schemas/HashMap"
                  }
                }
              }
            }
          },
          {
            "type": "object",
            "required": [
              "FooThingHashSet"
            ],
            "properties": {
              "FooThingHashSet": {
                "type": "object",
                "required": [
                  "foo"
                ],
                "properties": {
                  "foo": {
                    "$ref": "#/components/schemas/HashSet"
                  }
                }
              }
            }
          },
          {
            "type": "object",
            "required": [
              "FooThingBTreeSet"
            ],
            "properties": {
              "FooThingBTreeSet": {
                "type": "object",
                "required": [
                  "foo"
                ],
                "properties": {
                  "foo": {
                    "$ref": "#/components/schemas/BTreeSet"
                  }
                }
              }
            }
          }
        ]
      },
      "HashMap": {
        "type": "object",
        "additionalProperties": {
          "type": "string"
        },
        "propertyNames": {
          "type": "integer",
          "format": "int32"
        }
      },
      "HashSet": {
        "type": "array",
        "items": {
          "type": "integer",
          "format": "int32"
        },
        "uniqueItems": true
      },
      "LinkedList": {
        "type": "array",
        "items": {
          "type": "integer",
          "format": "int32"
        }
      },
      "Option": {
        "oneOf": [
          {
            "type": "null"
          },
          {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            }
          }
        ]
      },
      "Vec": {
        "type": "array",
        "items": {
          "type": "integer",
          "format": "int32"
        }
      }
    }
  }
}

Of course, we do not want refs to known/native generics. So I will add a test for type_tree.generic_type.is_none().

Sure, it also seems that the it still creates a reference to String for some reason.
diff --git a/utoipa-gen/tests/testdata/openapi_schemas_resolve_inner_schema_references b/utoipa-gen/tests/testdata/openapi_schemas_resolve_inner_schema_references
index 7368bc5..718e792 100644
--- a/utoipa-gen/tests/testdata/openapi_schemas_resolve_inner_schema_references
+++ b/utoipa-gen/tests/testdata/openapi_schemas_resolve_inner_schema_references
@@ -28,7 +28,7 @@
         {
           "properties": {
             "One": {
-              "type": "string"
+              "$ref": "#/components/schemas/String"
             }
           },
           "required": [
@@ -40,7 +40,7 @@
           "properties": {
             "Many": {
               "items": {
-                "type": "object"
+                "$ref": "#/components/schemas/String"
               },
               "type": "array"
             }
@@ -57,33 +57,7 @@
         {
           "properties": {
             "One": {
-              "properties": {
-                "accounts": {
-                  "items": {
-                    "oneOf": [
-                      {
-                        "type": "null"
-                      },
-                      {
-                        "$ref": "#/components/schemas/Account"
-                      }
-                    ]
-                  },
-                  "type": "array"
-                },
-                "foo_bar": {
-                  "$ref": "#/components/schemas/Foobar"
-                },
-                "name": {
-                  "type": "string"
-                }
-              },
-              "required": [
-                "name",
-                "foo_bar",
-                "accounts"
-              ],
-              "type": "object"
+              "$ref": "#/components/schemas/Yeah"
             }
           },
           "required": [
@@ -95,7 +69,7 @@
           "properties": {
             "Many": {
               "items": {
-                "type": "object"
+                "$ref": "#/components/schemas/Yeah"
               },
               "type": "array"
             }
@@ -231,6 +205,9 @@
       ],
       "type": "object"
     },
+    "String": {
+      "type": "string"
+    },
     "ThisIsNone": {
       "default": null
     },

Sure, it also seems that the it still creates a reference to String for some reason.

@juhaku weird, that change should fix it:
https://github.com/juhaku/utoipa/pull/1184/files#diff-e437cad9daa59d1d04f3511c45a3ff26a0626b664485d236fca0944598b77a24R563-R564

https://github.com/juhaku/utoipa/pull/1184/files#diff-e437cad9daa59d1d04f3511c45a3ff26a0626b664485d236fca0944598b77a24R563-R564

Yup that fixes, it but if you remove the inline from the arguments, the reference is created correctly for the Yeah, but not for the String. It has something to do with the way the schema references is created :thinking:

Yup that fixes, it but if you remove the inline from the arguments, the reference is created correctly for the Yeah, but not for the String. It has something to do with the way the schema references is created 🤔

Correct. But if you add the type_tree.generic_type.is_none() it covers this case too.

And I'm a bit puzzled by this one...

I have created a separate test: openapi_schemas_resolve_generic_enum_schema

True, that is a bit weird, I am trying to debug it as well.

Could it be specific to how enum schemas are handled?

FYI here is the expanded code:
mod response {
    use std::ops::Deref;
    use utoipa::{openapi::schema::ArrayItems, ToSchema};
    pub enum Element<T> {
        One(T),
        Many(Vec<T>),
    }
    impl<T> utoipa::__dev::ComposeSchema for Element<T>
    where
        T: utoipa::ToSchema,
    {
        fn compose(
            mut generics: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            Into::<
                utoipa::openapi::schema::OneOfBuilder,
            >::into(utoipa::openapi::OneOf::with_capacity(2usize))
                .item(
                    utoipa::openapi::schema::Object::builder()
                        .property(
                            "One",
                            {
                                let _ = <T as utoipa::PartialSchema>::schema;
                                if let Some(composed) = generics.get_mut(0usize) {
                                    std::mem::take(composed)
                                } else {
                                    utoipa::openapi::schema::RefBuilder::new()
                                        .ref_location_from_schema_name(
                                            ::alloc::__export::must_use({
                                                let res = ::alloc::fmt::format(
                                                    format_args!("{0}", <T as utoipa::ToSchema>::name()),
                                                );
                                                res
                                            }),
                                        )
                                        .into()
                                }
                            },
                        )
                        .required("One"),
                )
                .item(
                    utoipa::openapi::schema::Object::builder()
                        .property(
                            "Many",
                            utoipa::openapi::schema::ArrayBuilder::new()
                                .items({
                                    let _ = <T as utoipa::PartialSchema>::schema;
                                    if let Some(composed) = generics.get_mut(0usize) {
                                        std::mem::take(composed)
                                    } else {
                                        utoipa::openapi::schema::RefBuilder::new()
                                            .ref_location_from_schema_name(
                                                ::alloc::__export::must_use({
                                                    let res = ::alloc::fmt::format(
                                                        format_args!("{0}", <T as utoipa::ToSchema>::name()),
                                                    );
                                                    res
                                                }),
                                            )
                                            .into()
                                    }
                                }),
                        )
                        .required("Many"),
                )
                .into()
        }
    }
    impl<T> utoipa::ToSchema for Element<T>
    where
        T: utoipa::ToSchema,
    {
        fn name() -> std::borrow::Cow<'static, str> {
            std::borrow::Cow::Borrowed("Element")
        }
        fn schemas(
            schemas: &mut Vec<
                (String, utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>),
            >,
        ) {
            schemas.extend([]);
            <T as utoipa::ToSchema>::schemas(schemas);
            <T as utoipa::ToSchema>::schemas(schemas);
        }
    }
}

Could it be specific to how enum schemas are handled?

Could be, but hard to tell right away.

        fn schemas(
            schemas: &mut Vec<
                (String, utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>),
            >,
        ) {
            schemas.extend([]);
            <T as utoipa::ToSchema>::schemas(schemas);
            <T as utoipa::ToSchema>::schemas(schemas);
        }

Not sure if it's related, but the <T as utoipa::ToSchema>::schemas(schemas) x2 looks like an issue.
Otherwise the code generated for the One and Many alternative are pretty much exactly the same...

```rust

Not sure if it's related, but the ::schemas(schemas) x2 looks like an issue.

Yeah, it should not be an issue, but could also be fixed though, it in theory should result same spec but just redundantly calls the compose twice. There is no check whether the same reference call is already placed so it blindly adds schema reference call for each variant of the enum. Perhaps this could be fixed to the enum schema references implementation.

Alignment aside, the generated code is the same for the One and the Many.items variants:

Could it be that ArrayBuilder::items() behaves unexpectedly?

Could it be that ArrayBuilder::items() behaves unexpectedly?

Could be, as what dbg!(<Yeah as utoipa::PartialSchema>::schema()); returns, it returns correct schema, but when it is placed within the compose:
    let v = <Element<Yeah> as utoipa::__dev::ComposeSchema>::compose(
        [<Yeah as utoipa::PartialSchema>::schema()].to_vec(),
    );

This will result the invalid code for somehow.

It might have something to do with the utiopa/src/schema.rs ArrayItems default implementation, as It creates an empty object. I this might result the empty schema to be used instead :thinking:
impl Default for ArrayItems {
    fn default() -> Self {
        Self::RefOrSchema(Box::new(Object::with_type(SchemaType::AnyValue).into()))
    }
}

Could it be that ArrayBuilder::items() behaves unexpectedly?

Could be, as what dbg!(<Yeah as utoipa::PartialSchema>::schema()); returns, it returns correct schema, but when it is placed within the compose:
    let v = <Element<Yeah> as utoipa::__dev::ComposeSchema>::compose(
        [<Yeah as utoipa::PartialSchema>::schema()].to_vec(),
    );
    dbg!(&v);

This will result the invalid code for somehow.

IMO that compose() leads to impl<T: ComposeSchema> ComposeSchema for Vec<T>. And for T = String, it leads to the code generated by impl_compose_schema!(String) which generates:
impl ComposeSchema for String {
                fn compose(_: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
                    schema!( String ).into()
                }
            }

But I cannot find the schema! macro...

IMO that compose() leads to impl<T: ComposeSchema> ComposeSchema for Vec<T>. And for T = String, it leads to the code generated by impl_compose_schema!(String) which generates:

My bad. In the broken case, T = Vec<String>.

It might have something to do with the utoipa/src/schema.rs ArrayItems default implementation, as It creates an empty object. I this might result the empty schema to be used instead 🤔
impl Default for ArrayItems {
    fn default() -> Self {
        Self::RefOrSchema(Box::new(Object::with_type(SchemaType::AnyValue).into()))
    }
}

I've added a dbg!("ArrayItems::default"); in ArrayItems::default() and it is called when running the faulty test.

I've added a dbg!("ArrayItems::default"); in ArrayItems::default() and it is called when running the faulty test.

But changing its impl does not change the outcome of the test:
impl Default for ArrayItems {
    fn default() -> Self {
        dbg!("ArrayItems::default");
        Self::False
    }
}

So IMO the problem is elsewhere. No?

Now I know what happens :facepalm: the problem is mem::take it does not work for enums which are reusing same type for multiple variants. What ends up happening is that std::mem::take will remove the <Yeah as PartialSchema>::schema() for the first variant called One and replace it with empty object schema and the empty object schema is returned for the Many variant. :smile:

Now I know what happens 🤦 the problem is mem::take it does not work for enums which are reusing same type for multiple variants. What ends up happening is that std::mem::take will remove the <Yeah as PartialSchema>::schema() for the first variant called One and replace it with empty object schema and the empty object schema is returned for the Many variant. 😄

That makes perfect sense. Why taking away the generic in the first place?
Shouldn't that trigger the same problem for a struct with multiple field typed with the same type parameter?

That makes perfect sense. Why taking away the generic in the first place?

Idea was just to reuse memory, and avoid cloning, But true that would happen for structs using same type over and over again.
It seems the idea was more beautiful than the implementation.

Yeah, nice one :+1: It was some hard core debugging

Probably should consider migrating to vec of Rc<RefOr<Schema>> for reusing memory? 🤔

Probably. But out of scope for this PR if you don't mind :rofl:
The last failing test is derive_generic_schema_collect_recursive_schema_not_inlined, and IMO the ref is wrong.
77,89c77
<                   "type": "object",
<                   "required": [
<                     "t"
<                   ],
<                   "properties": {
<                     "t": {
<                       "type": "string",
<                       "enum": [
<                         "One",
<                         "Two"
<                       ]
<                     }
<                   }
---
>                   "type": "string"
100,112c88,92
<                   "type": "object",
<                   "required": [
<                     "t"
<                   ],
<                   "properties": {
<                     "t": {
<                       "type": "string",
<                       "enum": [
<                         "One",
<                         "Two"
<                       ]
<                     }
<                   }
---
>                   "type": "string",
>                   "enum": [
>                     "One",
>                     "Two"
>                   ]

FooStruct_BTreeMap_Ty_Ky_Person_Value.properties.foo.additionalProperties.properties.t  matches with Person<Value> and Value is a newtype for String. So the proper type is "string", but the reference says:
              "t": {
                  "type": "object",
                  "required": [
                    "t"
                  ],
                  "properties": {
                    "t": {
                      "type": "string",
                      "enum": [
                        "One",
                        "Two"
                      ]
                    }
                  }
                }

FooStruct_BTreeMap_Ty_Ky_Person_Value.properties.foo.propertyNames matches with Ty<Ky>, and Ky is the One | Two enum. So there is no reason to have a nested FooStruct_BTreeMap_Ty_Ky_Person_Value.properties.foo.propertyNames.t.properties.t.
I fixed the reference in 58405c8ea14e95e622e429696440e1eabcd4689b
@juhaku I'll you double check my changes made to the reference JSON files.

@juhaku I'll you double check my changes made to the reference JSON files.

Sure I check them out.

The last failing test is derive_generic_schema_collect_recursive_schema_not_inlined, and IMO the ref is wrong.

That is interesting, with my changes there is no more failing tests :thinking:  Though I did not add any inline args.

diff --git a/utoipa-gen/src/component.rs b/utoipa-gen/src/component.rs
index 5165196..70fb0a5 100644
--- a/utoipa-gen/src/component.rs
+++ b/utoipa-gen/src/component.rs
@@ -1259,11 +1259,12 @@ impl ComponentSchema {
                             path: Cow::Borrowed(&rewritten_path),
                             nullable,
                         };
-                        let index = if schema_type.is_primitive() {
-                            container.generics.get_generic_type_param_index(type_tree)
-                        } else {
-                            None
-                        };
+                        let index =
+                            if schema_type.is_primitive() || type_tree.generic_type.is_none() {
+                                container.generics.get_generic_type_param_index(type_tree)
+                            } else {
+                                None
+                            };

                         // forcibly inline primitive type parameters, otherwise use references
                         if index.is_none() {
@@ -1290,7 +1291,7 @@ impl ComponentSchema {
                                         let _ = <#rewritten_path as utoipa::PartialSchema>::schema;

                                         if let Some(composed) = generics.get_mut(#index) {
-                                            std::mem::take(composed)
+                                            composed.clone()
                                         } else {
                                             #item_tokens.into()
                                         }
diff --git a/utoipa-gen/tests/openapi_derive.rs b/utoipa-gen/tests/openapi_derive.rs
index bda75b9..d34d569 100644
--- a/utoipa-gen/tests/openapi_derive.rs
+++ b/utoipa-gen/tests/openapi_derive.rs
@@ -4,7 +4,7 @@ use assert_json_diff::{assert_json_eq, assert_json_include};
 use serde::Serialize;
 use serde_json::{json, Value};
 use utoipa::{
-    openapi::{schema, RefOr, Response, ResponseBuilder},
+    openapi::{schema, RefOr, Response, ResponseBuilder, Schema},
     OpenApi, ToResponse,
 };
 use utoipa_gen::ToSchema;
@@ -208,7 +208,7 @@ fn derive_openapi_with_servers() {
     #[openapi(
         servers(
             (url = "http://localhost:8989", description = "this is description"),
-            (url = "http://api.{username}:{port}", description = "remote api",
+            (url = "http://api.{username}:{port}", description = "remote api",
                 variables(
                     ("username" = (default = "demo", description = "Default username for API")),
                     ("port" = (default = "8080", enum_values("8080", "5000", "3030"), description = "Supported ports for the API"))
@@ -560,8 +560,8 @@ fn openapi_schemas_resolve_schema_references() {

     #[derive(ToSchema)]
     enum Element<T> {
-        One(#[schema(inline)] T),
-        Many(#[schema(inline)] Vec<T>),
+        One(T),
+        Many(Vec<T>),
     }

     #[derive(ToSchema)]
diff --git a/utoipa-gen/tests/testdata/openapi_schemas_resolve_inner_schema_references b/utoipa-gen/tests/testdata/openapi_schemas_resolve_inner_schema_references
index 7368bc5..9e0cd74 100644
--- a/utoipa-gen/tests/testdata/openapi_schemas_resolve_inner_schema_references
+++ b/utoipa-gen/tests/testdata/openapi_schemas_resolve_inner_schema_references
@@ -40,7 +40,7 @@
           "properties": {
             "Many": {
               "items": {
-                "type": "object"
+                "type": "string"
               },
               "type": "array"
             }
@@ -95,6 +95,32 @@
           "properties": {
             "Many": {
               "items": {
+                "properties": {
+                  "accounts": {
+                    "items": {
+                      "oneOf": [
+                        {
+                          "type": "null"
+                        },
+                        {
+                          "$ref": "#/components/schemas/Account"
+                        }
+                      ]
+                    },
+                    "type": "array"
+                  },
+                  "foo_bar": {
+                    "$ref": "#/components/schemas/Foobar"
+                  },
+                  "name": {
+                    "type": "string"
+                  }
+                },
+                "required": [
+                  "name",
+                  "foo_bar",
+                  "accounts"
+                ],
                 "type": "object"
               },
               "type": "array"
diff --git a/utoipa-gen/tests/testdata/schema_generics_openapi b/utoipa-gen/tests/testdata/schema_generics_openapi
index 95c429c..f69eda2 100644
--- a/utoipa-gen/tests/testdata/schema_generics_openapi
+++ b/utoipa-gen/tests/testdata/schema_generics_openapi
@@ -193,7 +193,7 @@
               "Many": {
                 "type": "array",
                 "items": {
-                  "type": "object"
+                  "type": "string"
                 }
               }

With this, if i run ./scripts/test.sh it will pass the checks.

True, that additionalProperties t value seems incorrect.

With this, if i run ./scripts/test.sh it will pass the checks.

I was testing with cargo test -p utoipa-gen. Let me run ./scripts/test.sh and remove the superfluous changes.

With this, if i run ./scripts/test.sh it will pass the checks.

I was testing with cargo test -p utoipa-gen. Let me run ./scripts/test.sh and remove the superfluous changes.

@juhaku ./scripts/test.sh utoipa-gen fails on generic_schema_full_api with:
    #[derive(ToSchema)]
    struct Person<'p, T: Sized, P> {
        id: usize,
        name: Option<Cow<'p, str>>,
        field: T,
        t: P,
    }

but passes with:
    #[derive(ToSchema)]
    struct Person<'p, T: Sized, P> {
        id: usize,
        name: Option<Cow<'p, str>>,
        #[schema(inline)]
        field: T,
        #[schema(inline)]
        t: P,
    }

@juhaku ./scripts/test.sh utoipa-gen fails on generic_schema_full_api with:

Okay, I'll check.

Without the inline on Person::field:
#[derive(ToSchema)]
    struct Person<'p, T: Sized, P> {
        id: usize,
        name: Option<Cow<'p, str>>,
        field: T,
        #[schema(inline)]
        t: P,
    }

the test fails and there is an unexpected $ref to #/components/schemas/String

@juhaku ./scripts/test.sh utoipa-gen fails on generic_schema_full_api with:

Okay, I'll check.

Ok you are right. Removing all the #[schema(inline)] in generic_schema_full_api make the test pass.
But adding some of them leads to unexpected behaviors such as this. or
It looks like the following change helps:
diff --git a/utoipa-gen/src/component.rs b/utoipa-gen/src/component.rs
index 70fb0a5..f51ea75 100644
--- a/utoipa-gen/src/component.rs
+++ b/utoipa-gen/src/component.rs
@@ -1259,12 +1259,13 @@ impl ComponentSchema {
                             path: Cow::Borrowed(&rewritten_path),
                             nullable,
                         };
-                        let index =
-                            if schema_type.is_primitive() || type_tree.generic_type.is_none() {
-                                container.generics.get_generic_type_param_index(type_tree)
-                            } else {
-                                None
-                            };
+                        object_schema_reference.is_inline =
+                            !schema_type.is_primitive() && type_tree.generic_type.is_some();
+                        let index = if !object_schema_reference.is_inline {
+                            container.generics.get_generic_type_param_index(type_tree)
+                        } else {
+                            None
+                        };

It looks like the following change helps:

Oh, nice, great.

@JMLX42 Getting back to the derive_generic_schema_collect_recursive_schema_not_inlined test that was failing with invalid schema for the BTreeMap. The following changes fixes this for the BTreeMap but this also indicates that the default implementation needs to be also changed for other type than the BTreeMap as well.
diff --git a/utoipa/src/lib.rs b/utoipa/src/lib.rs
index 7c9d666..57b16c1 100644
--- a/utoipa/src/lib.rs
+++ b/utoipa/src/lib.rs
@@ -1254,6 +1254,7 @@ impl_from_for_number!(
 pub mod __dev {
     use utoipa_gen::schema;

+    use crate::openapi::RefOr;
     use crate::{utoipa, OpenApi, PartialSchema};

     pub trait PathConfig {
@@ -1431,13 +1432,32 @@ pub mod __dev {
         }
     }

-    impl<K: ComposeSchema, T: ComposeSchema> ComposeSchema for std::collections::BTreeMap<K, T> {
+    impl<K: ComposeSchema + utoipa::ToSchema, T: ComposeSchema + utoipa::ToSchema> ComposeSchema
+        for std::collections::BTreeMap<K, T>
+    {
         fn compose(
             schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
         ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
+            fn schema_or_ref<V: ComposeSchema + utoipa::ToSchema>(
+                schemas: &[utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>],
+                index: usize,
+            ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
+                let _ = <V as utoipa::PartialSchema>::schema;
+                if let Some(composed) = schemas.get(index) {
+                    composed.clone()
+                } else {
+                    utoipa::openapi::schema::RefBuilder::new()
+                        .ref_location_from_schema_name(format!(
+                            "{}",
+                            <V as utoipa::ToSchema>::name()
+                        ))
+                        .into()
+                }
+            }
+
             utoipa::openapi::ObjectBuilder::new()
-                .property_names(Some(K::compose(schemas.clone())))
-                .additional_properties(Some(T::compose(schemas)))
+                .property_names(Some(schema_or_ref::<K>(&schemas, 0)))
+                .additional_properties(Some(schema_or_ref::<T>(&schemas, 1)))
                 .into()
         }
     }

The following changes fixes this for the BTreeMap but this also indicates that the default implementation needs to be also changed for other type than the BTreeMap as well.

Can you list me the other types to fix?

The following changes fixes this for the BTreeMap but this also indicates that the default implementation needs to be also changed for other type than the BTreeMap as well.

Can you list me the other types to fix?

Generally all the default ComposeSchema implementations in utiopa::__dev {} module according to the changes above. All of those implementations calls wrongly T::compose(..) But they need to be changed to above format to get the schema or to create ref.

It could be another PR though and I can also do that as well.

There is no need to change this though:
impl<T: ComposeSchema + ?Sized> PartialSchema for T {
    fn schema() -> crate::openapi::RefOr<crate::openapi::schema::Schema> {
        T::compose(Vec::new())
    }
}

All these should be changed:
    impl<T: ComposeSchema> ComposeSchema for Option<T> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            utoipa::openapi::schema::OneOfBuilder::new()
                .item(
                    utoipa::openapi::schema::ObjectBuilder::new()
                        .schema_type(utoipa::openapi::schema::Type::Null),
                )
                .item(T::compose(schemas))
                .into()
        }
    }

    impl<T: ComposeSchema> ComposeSchema for Vec<T> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            utoipa::openapi::schema::ArrayBuilder::new()
                .items(T::compose(schemas))
                .into()
        }
    }

    impl<T: ComposeSchema> ComposeSchema for std::collections::LinkedList<T> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            utoipa::openapi::schema::ArrayBuilder::new()
                .items(T::compose(schemas))
                .into()
        }
    }

    impl<T: ComposeSchema> ComposeSchema for [T] {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            utoipa::openapi::schema::ArrayBuilder::new()
                .items(T::compose(schemas))
                .into()
        }
    }

    impl<T: ComposeSchema> ComposeSchema for &[T] {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            utoipa::openapi::schema::ArrayBuilder::new()
                .items(T::compose(schemas))
                .into()
        }
    }

    impl<T: ComposeSchema> ComposeSchema for &mut [T] {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            utoipa::openapi::schema::ArrayBuilder::new()
                .items(T::compose(schemas))
                .into()
        }
    }

    impl<K: ComposeSchema, T: ComposeSchema> ComposeSchema for std::collections::HashMap<K, T> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            utoipa::openapi::ObjectBuilder::new()
                .property_names(Some(K::compose(schemas.clone())))
                .additional_properties(Some(T::compose(schemas)))
                .into()
        }
    }

    impl<K: ComposeSchema + utoipa::ToSchema, T: ComposeSchema + utoipa::ToSchema> ComposeSchema
        for std::collections::BTreeMap<K, T>
    {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            fn schema_or_ref<V: ComposeSchema + utoipa::ToSchema>(
                schemas: &[utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>],
                index: usize,
            ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
                let _ = <V as utoipa::PartialSchema>::schema;
                if let Some(composed) = schemas.get(index) {
                    composed.clone()
                } else {
                    utoipa::openapi::schema::RefBuilder::new()
                        .ref_location_from_schema_name(format!(
                            "{}",
                            <V as utoipa::ToSchema>::name()
                        ))
                        .into()
                }
            }

            utoipa::openapi::ObjectBuilder::new()
                .property_names(Some(schema_or_ref::<K>(&schemas, 0)))
                .additional_properties(Some(schema_or_ref::<T>(&schemas, 1)))
                .into()
        }
    }

    impl<K: ComposeSchema> ComposeSchema for std::collections::HashSet<K> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            utoipa::openapi::schema::ArrayBuilder::new()
                .items(K::compose(schemas))
                .unique_items(true)
                .into()
        }
    }

    impl<K: ComposeSchema> ComposeSchema for std::collections::BTreeSet<K> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            utoipa::openapi::schema::ArrayBuilder::new()
                .items(K::compose(schemas))
                .unique_items(true)
                .into()
        }
    }

    #[cfg(feature = "indexmap")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "macros", feature = "indexmap")))]
    impl<K: ComposeSchema, T: ComposeSchema> ComposeSchema for indexmap::IndexMap<K, T> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            utoipa::openapi::ObjectBuilder::new()
                .property_names(Some(K::compose(schemas.clone())))
                .additional_properties(Some(T::compose(schemas)))
                .into()
        }
    }

    #[cfg(feature = "indexmap")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "macros", feature = "indexmap")))]
    impl<K: ComposeSchema> ComposeSchema for indexmap::IndexSet<K> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            utoipa::openapi::schema::ArrayBuilder::new()
                .items(K::compose(schemas))
                .unique_items(true)
                .into()
        }
    }

    impl<'a, T: ComposeSchema + Clone> ComposeSchema for std::borrow::Cow<'a, T> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            T::compose(schemas)
        }
    }

    impl<T: ComposeSchema> ComposeSchema for std::boxed::Box<T> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            T::compose(schemas)
        }
    }

    impl<T: ComposeSchema> ComposeSchema for std::cell::RefCell<T> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            T::compose(schemas)
        }
    }

    #[cfg(feature = "rc_schema")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "macros", feature = "rc_schema")))]
    impl<T: ComposeSchema> ComposeSchema for std::rc::Rc<T> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            T::compose(schemas)
        }
    }

    #[cfg(feature = "rc_schema")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "macros", feature = "rc_schema")))]
    impl<T: ComposeSchema> ComposeSchema for std::sync::Arc<T> {
        fn compose(
            schemas: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
        ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
            T::compose(schemas)
        }
    }

I tried to remove some #[schema(inline)]. Apparently:

it works when the schema is passed to request_body (cf derive_path_test_collect_generic_array_request_body) :heavy_check_mark:
it does not work when passed tocomponents(schemas()) (cf derive_generic_schema_collect_recursive_schema_not_inlined).

I've added a new test that highlights the issue: generic_request_body_schema.

I tried to remove some #[schema(inline)]. Apparently:
* it works when the schema is passed to `request_body` (cf `derive_path_test_collect_generic_array_request_body`) ✔

* it does _not_ work when passed to`components(schemas())` (cf `derive_generic_schema_collect_recursive_schema_not_inlined`) ❌.

I've added a new test that highlights the issue: generic_request_body_schema.
Update: I think those problems now come from the if is_inlined branch.

Right, indeed it creates the weird references., I'll check this too. You are right it might just be in the is_inline side the error now.

@JMLX42
Now this comes to a bit annoying point. The inline was not defined for the compose at all. So what the inline does it actually calls ::schema() function in hopes of getting the schema. while this works for normal types, it does not work for generic types which are composed.
E.g. If we have type like this below. And provide a generic type for P called Type<i32>. What ends up happening is it ends up calling P::schema() which is same as calling <Type<i32> as PartialSchema>::schema() which equals to <Type<i32> as ComposeSchema>::compose(Vec::new()). So what happens here is that it calls compose with empty generics array and it makes the type a reference.
 // #[derive(ToSchema)]
struct Person<T: Sized, P> {
    field: T,
    // #[schema(inline)]
    t: P,
}

let person = <Person<String, Type<i32>> as utoipa::__dev::ComposeSchema>::compose(
    [
        <String as utoipa::PartialSchema>::schema(),
        <Type<i32> as utoipa::__dev::ComposeSchema>::compose(
            [<i32 as utoipa::PartialSchema>::schema()].to_vec(),
        ),
    ]
    .to_vec(),
);
dbg!(person);

This is what gets generated for Person and note here because of aforementioned #[schema(inline)] the P is called as  P::schema() but because it is a generic type it actually should be called with P::compose(args).
impl<T: Sized, P> utoipa::__dev::ComposeSchema for Person<T, P>
where
    T: utoipa::ToSchema,
    P: utoipa::ToSchema,
{
    fn compose(
        mut generics: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
    ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
        {
            let mut object = utoipa::openapi::ObjectBuilder::new();
            object = object
                .property("field", {
                    let _ = <T as utoipa::PartialSchema>::schema;
                    if let Some(composed) = generics.get_mut(0usize) {
                        composed.clone()
                    } else {
                        utoipa::openapi::schema::RefBuilder::new()
                            .ref_location_from_schema_name(format!(
                                "{}",
                                <T as utoipa::ToSchema>::name()
                            ))
                            .into()
                    }
                })
                .required("field");
            let p = <P as utoipa::PartialSchema>::schema();
            dbg!("got p", &p);
            object = object
                .property("t", p)
                .required("t");
            object
        }
        .into()
    }
}

The problem is here:
https://github.com/JMLX42/utoipa/blob/4ca70bdf0146bb05a8da4035d6a06ec4f5cbcbae/utoipa-gen/src/component.rs#L1220-L1233
We somehow should resolve here the actual type of P and depending whether it is a generic type it would call compose instead if schema. But I am not sure whether it actually is possible. Now the compose is called when has children` meaning that it actually has generic children.

If I change the implementation to this:
diff --git a/utoipa-gen/src/component.rs b/utoipa-gen/src/component.rs
index 70fb0a5..f6f1f68 100644
--- a/utoipa-gen/src/component.rs
+++ b/utoipa-gen/src/component.rs
@@ -1228,7 +1228,8 @@ impl ComponentSchema {
                             }
                         } else {
                             quote_spanned! {type_path.span()=>
-                                <#rewritten_path as utoipa::PartialSchema>::schema()
+                                // <#rewritten_path as utoipa::PartialSchema>::schema()
+                                <#rewritten_path as utoipa::__dev::ComposeSchema>::compose(generics.clone())
                             }
                         };
                         object_schema_reference.tokens = items_tokens.clone();

I get following error:
1. the trait bound `P: utoipa::__dev::ComposeSchema` is not satisfied
   the trait `utoipa::__dev::ComposeSchema` is not implemented for `P` [E0277]

Because P does not implement ComposeSchema and it is not required to be implemented. :face_exhaling:
This kind of gets to point where the generics implementation in general needs some adjustment e.g. it should go ComposeSchema first and make sure everything implements it in first place. :thinking:
impl<T: Sized, P> utoipa::__dev::ComposeSchema for Person<T, P>
where
    T: utoipa::ToSchema,
    P: utoipa::ToSchema,
{
    fn compose(
        mut generics: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
    ) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
        {
            let mut object = utoipa::openapi::ObjectBuilder::new();
            object = object
                .property("field", {
                    let _ = <T as utoipa::PartialSchema>::schema;
                    if let Some(composed) = generics.get_mut(0usize) {
                        composed.clone()
                    } else {
                        utoipa::openapi::schema::RefBuilder::new()
                            .ref_location_from_schema_name(format!(
                                "{}",
                                <T as utoipa::ToSchema>::name()
                            ))
                            .into()
                    }
                })
                .required("field");
            object = object
                .property(
                    "t",
                    <P as utoipa::__dev::ComposeSchema>::compose(generics.clone()),
                )
                .required("t");
            object
        }
        .into()
    }
}

Another problem: I did all of this because I wanted my responses to properly use ref for there type parameter.
Here is my code:
#[derive(Debug, Serialize, ToSchema)]
pub struct SuccessResponsePayload<T: ResourceObject> {
    #[schema(inline = false)]
    pub data: Vec<T>,
    #[schema(ignore = Self::ignore_included)]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub included: Option<Vec<T::RelationshipValue>>,
    #[schema(inline)]
    pub links: LinksObject<T>,
}

impl<T: ResourceObject> SuccessResponsePayload<T> {
    fn ignore_included() -> bool {
        !T::HAS_RELATIONSHIPS
    }
}

#[derive(Debug, Serialize, IntoResponses, ToSchema)]
#[serde(untagged)]
pub enum Response<T: ResourceObject> {
    #[response(
        status = 204,
        content_type = CONTENT_TYPE,
        description = "Success response with no content.",
    )]
    Empty,
    #[response(
        status = 200,
        content_type = CONTENT_TYPE,
        description = "Success response."
    )]
    Success(#[to_schema] SuccessResponsePayload<T>),
    #[response(
        status = "4XX",
        content_type = CONTENT_TYPE,
        description = "Client error response.",
        example = json!(EXAMPLE_ERROR_NOT_FOUND)
    )]
    ClientError(#[to_schema] ClientErrorResponse),
    #[response(
        status = "5XX",
        content_type = CONTENT_TYPE,
        description = "Server error response.",
        example = json!(EXAMPLE_ERROR_INTERNAL_SERVER_ERROR)
    )]
    ServerError(#[to_schema] ServerErrorResponse),
}

For some reason, SuccessResponsePayload::data is still inlined :cry: . I'll write a specific test for this scenario tomorrow.

Now this comes to a bit annoying point. The inline was not designed for the compose at all 😆. It was there before the compose was a thing. So what the inline does it actually calls ::schema() function in hopes of getting the schema. while this works for normal types, it does not work for generic types which are composed.

The generic_request_body_schema passes if we inline all the way down though:
    #[derive(ToSchema)]
    #[schema(as = path::MyType<T>)]
    struct Type<T> {
        #[schema(inline)] // <= this is the change
        t: T,
    }

    #[derive(ToSchema)]
    struct Person<T: Sized, P> {
        field: T,
        #[schema(inline)]
        t: P,
    }

Yeah those ToResponse and IntoResponses have not been touched in this in this 5.0.0 release other than just to make it work. But they are not guaranteed to actually do the right thing. That is perhaps a topic of own.

The generic_request_body_schema passes if we inline all the way down though:

That works because the compose implementation for the Type<i32> returns either given composed generic type or a reference by default. If inline is used within the Type<i32> it will no use the compose implementation but directly call i32::schema() eventually and use that as the return value for Type<i32> compose function instead. This results the fact that whether <Type>::schema() or <Type>::compose(any_vec) is called they both return the i32::schema().

Can the generated code check if the type is in generics and call compose() or schema() accordingly?

That's probably the expected goal of generics.get_mut() here.
But the same check is not performed for the if is_inline branch. Maybe that's what's missing.

Can the generated code check if the type is in generics and call compose() or schema() accordingly?

That's probably the expected goal of generics.get_mut() here.
But the same check is not performed for the if is_inline branch. Maybe that's what's missing.

https://github.com/juhaku/utoipa/blob/c45215c303ab288ed132a487c4b86b00b9513573/utoipa-gen/src/component.rs#L1220
The check is actually here it checks whether it has chidren, but in above case at that point it sees P as type which does not have children and not Type<i32>.

The check is actually here it checks whether it has chidren, but in above case at that point it sees P as type which does not have children and not Type<i32>.

Yes that's what I figured. But that's done at the macro time, not at runtime. Can't we have a better check at runtime using generics.get_mut()?

Yes that's what I figured. But that's done at the macro time, not at runtime. Can't we have a better check at runtime using generics.get_mut()?

I mean at some point, some code generates a "$ref": "#/components/schemas/i32" which does not make sense. I am having a hard time pinpointing where that code is.

generics.get_mut()?

I mean at some point, some code generates a "$ref": "#/components/schemas/i32" which does not make sense. I am having a hard time pinpointing where that code is.

Yeah, not sure whether there is any way to actually get around this.But the inline is taken out form the t it will work just fine, that is because it will go to the else block where it generates the type like shown below with the generics.get_mut(generics).

   #[derive(ToSchema)]
   #[schema(as = path::MyType<T>)]
   struct Type<T> {
       #[schema(inline)] // <= this is the change
       t: T,
   }

   #[derive(ToSchema)]
   struct Person<T: Sized, P> {
       field: T,
       //#[schema(inline)]       // <--- here
       t: P,
   }

object = object
    .property("t", {
        let _ = <P as utoipa::PartialSchema>::schema;
        if let Some(composed) = generics.get_mut(1usize) {
            composed.clone()
        } else {
            utoipa::openapi::schema::RefBuilder::new()
                .ref_location_from_schema_name(format!(
                    "{}",
                    <P as utoipa::ToSchema>::name()
                ))
                .into()
        }
})
.required("t");

What's more is that when type type is E.g. wrapped with another type like in below example. If it is inlined with #[schema(inline)] it will create a reference to the type :rofl: But if it is not inlined, It will not create a reference but will just directly inline the type when Person<T, P> is being used. After all it was designed so that it will directly inline the generic arguments.
    #[derive(ToSchema)]
    struct Wrapper {
        value: i32
    }

    #[derive(ToSchema)]
    struct Person<T: Sized, P> {
        field: T,
        #[schema(inline)]
        t: P,
    }

If we change the if is_inline branch like the following, then whether #[schema(inline)] is defined or not, the result will always be inlined.
diff --git a/utoipa-gen/src/component.rs b/utoipa-gen/src/component.rs
index 70fb0a5..216e22d 100644
--- a/utoipa-gen/src/component.rs
+++ b/utoipa-gen/src/component.rs
@@ -1227,8 +1227,20 @@ impl ComponentSchema {
                                 <#rewritten_path as utoipa::__dev::ComposeSchema>::compose(#composed_generics.to_vec())
                             }
                         } else {
-                            quote_spanned! {type_path.span()=>
-                                <#rewritten_path as utoipa::PartialSchema>::schema()
+                            let index = container.generics.get_generic_type_param_index(type_tree);
+                            dbg!("inline got index", index, &rewritten_path);
+                            if index.is_some() {
+                                quote_spanned! {type_path.span()=>
+                                    if let Some(composed) = generics.get(#index) {
+                                        composed.clone()
+                                    } else {
+                                        <#rewritten_path as utoipa::PartialSchema>::schema()
+                                    }
+                                }
+                            } else {
+                                quote_spanned! {type_path.span()=>
+                                    <#rewritten_path as utoipa::PartialSchema>::schema()
+                                }
                             }
                         };
                         object_schema_reference.tokens = items_tokens.clone();

@juhaku how about:

we document this edge case
we open a separate issue to track the fix

?

@JMLX42 I guess that is what we need to do. Otherwise this will never end. :laughing:

I guess that is what we need to do. Otherwise this will never end.

#1197

@juhaku ready for review!

I guess with this the schema(inline) behavior will become bit unstable for generic arguments as can be seen from above discussions. I'll add more documentation for the inline attribute regarding this.

Could we get this in a new release? Thanks!


Upgrade to serde 1.0

I am working on this.

Ok, I've updated cbor to serde 1.0 and all tests pass. Can you please have a look at the code before I release? (There is an alpha version on crates.io)
PS: I currently do not use this crate but it got somewhat popular. Because I do not have this much time any more it would be great if someone else would maintain it. Maybe it can live at the serde-rs organization? After serde has reached 1.0 there are probably not that many updates needed.

Thanks!
@dtolnay thoughts on a transfer to the serde org? ^

I would prefer not to transfer to the serde-rs org because I don't have the bandwidth to own this crate. IIRC this crate is pretty important to you, can you or someone on the team own it?

@pyfisch the bound on from_reader should be T: DeserializeOwned - see this page. Also it would be great to support zero-copy deserialization as part of this. That involves parse_string and parse_bytes calling visit_borrowed_str and visit_borrowed_bytes if the input is a &'de [u8].

Perhaps @BurntSushi could take over in lieu of implementing https://github.com/BurntSushi/rust-cbor/issues/3?

Hi! I think CBOR is quite similar with JSON so in that sense serde-rs would be a logical place. Unfortunate if it does not fit there. As a crate user I'd appreciate a long term solution anyway.

I'd be happy to poke at supporting zero copy deserialization, but it'd be great to get a release with the changes you've already made in the mean time.

Released as v0.6.0.

Remaining work filed as #31 and #32.

Awesome, thank you!


I built a site with Eleventy!

https://github.com/johanbrook/johanbrook.com
http://johanbrook.com

Looks great—thanks!
I think this was was already on the site though https://www.11ty.io/docs/#sites-using-eleventy

Haha, very lol. Sorry! Totally forgot that while browsing the docs! :D

😇 no worries!


Pit teleport endless loop

Details
During pit run, sometimes the bot gets stuck in an endless loop trying to teleport past a curve in the map, it just goes back and forth forever, or until the time runs out.
Version
dev

I've run into this quite a bit as well. it seems from the log its trying to get to a mob and is "reducing max attack distance" but it just goes back and forth untill it hits a timeout it seems.
time=13:54:02 level=DEBUG msg="Looks like monster is not reachable, reducing max attack distance."
time=13:54:02 level=DEBUG msg="Looks like monster is not reachable, reducing max attack distance."
time=13:54:03 level=DEBUG msg="Looks like monster is not reachable, reducing max attack distance."
time=13:54:05 level=DEBUG msg="Looks like monster is not reachable, reducing max attack distance.

commit: e0840d6eb2ec1cc4dbb2711717422fd223d1febe
still cant seem to get the latest commit to work for me.

Any fix to this?


package does not build with latest GHC and stack LTS

Package does not build past LTS-10.10. It would be nice to be able to build on GHC 8.6.

I did stack build and It compiled. Did you tried simply stack build?

It builds with the old package set specified in the Stack file; it does not build with newer Stack package sets.
This repo is deprecated and very out of date. The most current version of this library is at https://github.com/dimitri-xyz/coinbase-pro-exchange.


Lighthouse 44 patch: taking into account jvm.memory

Hi! Any interest in this one?

this problem has effected me too, it would be very helpful as a 1.2.x fix


brief response attachment upload

Need to make changes:

base route in routes.js
create a Page with sub routes, redux, etc
stateless form
lots of little eslint errors now the new rules are switched on

Form now stateless and accessed via a Page

fixed and rebased :)


[DO NOT MERGE] Spacetime build

See if spacetime can reveal memory leak.

Closing but keeping branch around for future use.

Note for the curious: we don't care that most of the CI jobs fail, because it's mostly expected out-of-memory errors.
The purpose of the PR is to build a .deb for medium curves, so we can run a spacetime node.

Superseded by #3471.


Postgres IaC management

This PR is a follow up to #117 which adds support for managing the Postgres deployment through Argo CD.
In fact, the Postgres manifests are tied to an Argo CD app in the mesh infra project so we can easily manage deployments through a GUI too. Ditto for the storage and security.

Demo steps

Log in to Argo CD: http://kitt4sme.collab-cloud.eu/argocd/
Select the platform infra project
Check there's an app for Postgres
Click through to the details page and check all the Postgres resources declared in the manifests are there


Good metrics for model evaluation?

Hi!
Context
Before proceeding with more work on modeling & features, I think it would be useful to make sure that we are tracking good metrics to evaluate the output of the models.
I my last PR, I introduced basic canonical multi-class metrics (Sklearn's classification_report
) using the labelled dataset (efo_otar_slim_v3.43.0_rs_classification.tsv):
                    precision    recall  f1-score   support

01-disease-subtype       0.80      0.85      0.82      1123
   02-disease-root       0.72      0.64      0.68       776
   03-disease-area       0.77      0.79      0.78       242
    04-non-disease       0.97      0.99      0.98       918

          accuracy                           0.83      3059
         macro avg       0.82      0.82      0.82      3059
      weighted avg       0.83      0.83      0.83      3059

Question
⇒ Have you done work internally to evaluate classification metrics and how well they correlate to business goals?

Have you done work internally to evaluate classification metrics and how well they correlate to business goals?

I'd have a minor preference for ROC, but F1 is ok too (ideally both when not picking one for optimization).
I will say though that I think support-weighted averages are definitely bad here since 03-disease-area is both the least frequent and most important (for us) class to identify correctly.  An evenly weighted macro-average is fine for a single score across all classes, though a better weighting IMO is {'03-disease-area': .5, '02-disease-root': .25, '01-disease-subtype':  .25}.
The 04-non-disease class should be irrelevant since it's determined by the ontology structure rather than being a part of the training/prediction problem.

I prefer macro averaged mean absolute error, where each class could be evenly weighted or even better customizeable like @eric-czech suggested.
I'm assuming the predicted classes are fuzzy (i.e. probabilities rather than binary) and sum to 1 for a given sample across all classes.
References all in the context of ordinal classification instead of nominal/categorical classification:

https://stats.stackexchange.com/a/375956/74908
https://github.com/scikit-learn/scikit-learn/issues/18901
https://github.com/scikit-learn-contrib/imbalanced-learn/pull/780. In this context, it's called macro_averaged_mean_absolute_error

Not sure if the sklearn mean_absolute_error function can work with categorical. I've only ever used this metric for binary classification.
Here's how I envision the computation working for a specific sample:

Class
Truth
Prediction
Abs Error

01-disease-subtype
1
0.6
0.4

02-disease-root
0
0.3
0.3

03-disease-area
0
0.1
0.1

04-non-disease
0
0.0
0.0

Then we average the absolute error for all samples within each class. Then we average the within-class mae by the macro-weights to get the single output score.
The score is between 0 for perfect and 1 for exactly opposite. I like this metric because it accounts for how off a prediction rather than applying only after the predictions are binarized and most information is lost. It's especially important if we have a case where we're interested in fuzzy predictions (for this project, perhaps less so). A mamae of 0.1 would indicate that after our macro-averaging each prediction is 0.1 away from truth.
I'm not sure why it's not the most common metric for all classification problems. Convince me it's bad haha.
That being said, I leave what metric to use as something that is up to you the implementer.

Cool, that works for me. I'll give it a spin and open a corresponding PR.

support-weighted averages are definitely bad here since 03-disease-area is both the least frequent and most important (for us) class to identify correctly

Great to know, thanks for the insight! This class imbalance has an interesting impact on the model and its business outcome.
@eric-czech Do you think it'd be worth trying to come up with a somewhat solid estimate for the class weights and inject that into the training objective?

I like this metric because it accounts for how off a prediction rather than applying only after the predictions are binarized and most information is lost.

@dhimmel  I think this metric makes a lot of sense, I just wonder how correlated it is to a binary error (once averaged over a lot of samples). I don't see how the extra information can hurt, I'll give it a try.
Also, I noticed that this metric is mostly used for ordinal classification..
=> Do we have an ordinal relationship between classes here? (e.g. from more to least specific)

I'm not sure why it's not the most common metric for all classification problems. Convince me it's bad haha.

FWIW I could hypothesize why MAE would be less popular as objective functions than binary type losses:

Strongly correlated to binary metrics & more work to compute
Less easy to vectorize, makes the training loop slower
Less aligned with the classification task? (pick the top scoring class and ignore the rest)

Example with 3 classes:
y^hat = [1, 0, 0]
y_1 = [0.32, 0.34, 0.34]  => mae(y_1) = 1.36
y_2 = [0.34, 0.33, 0.33] => mae(y_2) = 1.32

y_1 would yield the wrong class and y_2 would yield the right class, but their gradient update would be pretty much the same. Using a binary loss would apply a more differentiated update.
But I agree that it should be a stronger metric in the case where the classes are more fuzzy (unless training speed is more valuable than a better objective function?)

@eric-czech Do you think it'd be worth trying to come up with a somewhat solid estimate for the class weights and inject that into the training objective?

Yep, I'm onboard with that.  50% for disease area, 25% for the other two feels right to me.

ordinal classification

That's a great angle here.  I always finding it a little frustrating how poor support is for that in most ML libs with canned implementations.  If you're interested, that's definitely worth exploring more since it makes interpretability much cleaner.

Thanks @yonromai for your explanation and thoughts. Regarding the proposed mamae metric, feel free to only use it when reporting on the final models rather than as an objective function.

Do we have an ordinal relationship between classes here? (e.g. from more to least specific)

Hmm. Yes I think we could consider this ordinal. If a term is truthfully high specificity, calling it low specificity would appear to be more egregious of an error than calling it medium specificity. But using a nominal multiclassifier is also okay.

As per experimental results, it seems like the metrics discussed above are good enough for now? I'm going to close this issue for now.
Feel free to re-open if you disagree / have anything else to add.


Warn when toll_gantry on highway without toll=yes

Description
From the OSM wiki on toll_gantry:
"The way that the node is placed on must also be tagged with toll=yes on any applicable road segments."
Could iD issue a warning whenever this is not the case?
Screenshots
No response

Can you assigned to me?

I have never assigned anything, and I am not sure i have the power. I will assume we need someone else to assign it to you.

I saw other issues, I think we can't/don't assign.
I halfly solved, "I've managed to resolve about half of the issue. However, when I added a new missing tag condition, I encountered an 'en-transition' error. If I use the original variable name for the new missing tag condition, the error is resolved, but then the message name isn't clear.

(it means that if I use same subtype like UnknownRoad then it doesnt occur error message, but it shows not our expected  message)
Btw, Condition is satisfied your requirment (For highways and motorways that have tollgates but are taged as 'toll=no', display a warning)

I solved all, I will pull request


Pass over the owner ship of the gem

We had a conversation by email that you no longer have a active project with lightbox.
I'm more then happy to take over the ownership of the gem.
Please add me as the new oner on rubygems.

@johansmitsnl I would open an issue with Ruby Gems directly and see what they can do, as your fork works and this repo does not. The repo owner clearly can't be arsed to merge in your pull request or reply to you. http://help.rubygems.org/discussion/new

@benbarber that sounds good. Let me know what the outcome is.

@benbarber any news?

Unfortunately not, I did open an issue with Ruby Gems Support but have had no response.

I will be adding CI/CD and publish a newer version with Lightbox 2.10.0.

@gavinkflam good to see your back!
Are you interesting in adding me as a contributor to the project?


Master rpm

Fixes a couple of issues with running packaging/opae/rpm/create for master on fedora 34

dropped the n3000 test change.  maybe this was causing the unit test failure?

@trixirt , I think the n3000 unit test failure is because of some outdated sysfs paths.
#1965 should fix this (🤞)

ok that makes sense, thanks!

Coverage decreased (-0.03%) to 66.196% when pulling 5ffcd0eb92262b25b9a4aeea1d5ac6f1b875fa62 on trixirt:master-rpm into 09274693ef595184ab66f1a7feac5fd586b28e53 on OPAE:master.

create on fedora is now only failing in rpmbuild from built but not installed python bits

a d5005 unit test failure.  Only rpm changes made so these changes are not likely to blame

new commit is a new problem with opae-libs/scripts/ofs/ofs_parse.py

Nothing changed, just rebased to current master.


libproc.h file not found fix: ducktape include directories so that builds on mac os are successful

Compiling libproc v0.12.0
error: failed to run custom build command for `libproc v0.12.0`

Caused by:
  process didn't exit successfully: `<PROJECT PATH>/target/debug/build/libproc-7ab682cfcd895988/build-script-build` (exit status: 101)
  --- stderr
  <HOME>/.cargo/registry/src/github.com-1ecc6299db9ec823/libproc-0.12.0/libproc_rs.h:1:10: fatal error: 'libproc.h' file not found
  <HOME>/.cargo/registry/src/github.com-1ecc6299db9ec823/libproc-0.12.0/libproc_rs.h:1:10: fatal error: 'libproc.h' file not found, err: true
  thread 'main' panicked at 'Failed to build libproc bindings: ()', <HOME>/.cargo/registry/src/github.com-1ecc6299db9ec823/libproc-0.12.0/build.rs:9:10
  stack backtrace:
     0: rust_begin_unwind
               at /rustc/62b272d25c5bb8b6bb8ac73797d82b8b9a1eabda/library/std/src/panicking.rs:584:5
     1: core::panicking::panic_fmt
               at /rustc/62b272d25c5bb8b6bb8ac73797d82b8b9a1eabda/library/core/src/panicking.rs:142:14
     2: core::result::unwrap_failed
               at /rustc/62b272d25c5bb8b6bb8ac73797d82b8b9a1eabda/library/core/src/result.rs:1805:5
     3: core::result::Result<T,E>::expect
               at /rustc/62b272d25c5bb8b6bb8ac73797d82b8b9a1eabda/library/core/src/result.rs:1055:23
     4: build_script_build::main
               at ./build.rs:6:20
     5: core::ops::function::FnOnce::call_once
               at /rustc/62b272d25c5bb8b6bb8ac73797d82b8b9a1eabda/library/core/src/ops/function.rs:248:5
  note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Also see  https://github.com/andrewdavidmackenzie/libproc-rs/issues/82
Test plan:

$ make: build is successful
test suite passes

Thanks @jrabinow for the contribution. I will publish a new patch version on crates.io after this.
Subscribe to releases in GH notifications if you want.
FYI @micouy  @sporkmonger


Make private members to be protected for DefaultVsCodeKieEditorChannelApiImpl

Is it possible to make the private constructor arguments protected in the DefaultVsCodeKieEditorChannelApiImpl class class?
In the DefaultVsCodeKieEditorChannelApiImpl class, all of its members are private, making complicated for other classes extending it to use them.
Here's an extract of the constructor:
export class DefaultVsCodeKieEditorChannelApiImpl implements KogitoEditorChannelApi, JavaCodeCompletionChannelApi {
  constructor(
-    private readonly editor: VsCodeKieEditorController,
-    private readonly resourceContentService: ResourceContentService,
-    private readonly workspaceApi: WorkspaceChannelApi,
-    private readonly backendProxy: BackendProxy,
-    private readonly notificationsApi: NotificationsChannelApi,
-    private readonly javaCodeCompletionApi: JavaCodeCompletionApi,
-    private readonly viewType: string,
-    private readonly i18n: I18n<VsCodeI18n>
+    protected readonly editor: VsCodeKieEditorController,
+    protected readonly resourceContentService: ResourceContentService,
+    protected readonly workspaceApi: WorkspaceChannelApi,
+    protected readonly backendProxy: BackendProxy,
+    protected readonly notificationsApi: NotificationsChannelApi,
+    protected readonly javaCodeCompletionApi: JavaCodeCompletionApi,
+    protected readonly viewType: string,
+    protected readonly i18n: I18n<VsCodeI18n>
  ) {}

The goal is to access the underlying file path from the API.
For instance, doing something like the following:
method() {
    const uri = this.editor.document.document.uri;
}

@lordrip No objections at all. Feel free to send a PR.

If this is something you absolutely need ASAP, consider bringing this to<EMAIL_ADDRESS>as version 10.0 is frozen for features already, and it might be a few months until we're able to release 10.1.

Hi @tiagobento, thanks, since 10.0 is frozen, it's ok to wait for the next release, I'll prepare a PR and you decide when is a good moment to include it, we're not blocked, we have a workaround in the meantime :v:


chore(master): release 1.1.19

:robot: I have created a release beep boop
1.1.19 (2023-08-15)
Bug Fixes

deps: update dependency wayofdev/laravel-cycle-orm-adapter to v4.0.61 (c977083)

This PR was generated with Release Please. See documentation.

:robot: Release is at https://github.com/wayofdev/laravel-webhook-client/releases/tag/v1.1.19 :sunflower:


Create empty slice when records are not found.

There is a gotcha in golang (go figure!) resulting from the
difference between a nil slice and an empty slice. While the length
of both are 0, the JSON encoder will interpret the nil slice as
null and the empty slice as []. Other libraries (i.e. ActiveRecord)
will return [] when no values are found. I have found
that this translates into better client-side code, since you don't
have to protect against null arrays.
See this for more information.

So why was this closed? Returning nil when no association was found is not correct, it should be empty array. I think this should be handled by gorm.


how should I set an description for 2902 based code`/

Hi h2zero,
I have a bit a problem getting things done with 2902 based stuff. I tried self several ways - researched a little - had a look to this keyboard stuff of sivar2311. But I didn't get it. I'm a real newbie in the area of BLE.
I searched also for examples in the NewBLE-library but nothing to find what is a bit alike what I want to do.
Can you help me?
Here my code to convert to using NimBLED from using the original BLE Library:
NimBLECharacteristic* pCharacteristicTEMP = pBmeService->createCharacteristic(TEMP_UUID, NIMBLE_PROPERTY::NOTIFY);

BLEDescriptor* pBLEDescriptorTEMP = pCharacteristicTEMP->createDescriptor(BLEUUID((uint16_t)0x2902));
pBLEDescriptorTEMP->setValue("BME temperature Celsius");
pCharacteristicTEMP->addDescriptor(pBLEDescriptorTEMP);

These last 3 lines: how I have to implement this in the NimBLE-way?
Jop

In this library the 2902 is automatic when the characteristic has the notification property. You need to delete those 3 lines.

Not quite clear to me. How the descriptor will get its content in this "2902-automatic" way?
Here my more complete code that makes difference between Celsius and Fahrenheit, dependent of a compiler directive.
  // Create NimBLE Characteristics and Create a NimBLE Descriptor
  // Temperature
  #ifdef temperatureCelsius
    pCharacteristicTEMP = pBmeService->createCharacteristic(TEMP_UUID, NIMBLE_PROPERTY::NOTIFY);

    NimBLEDescriptor* pNimBLEDescriptorTEMP = pCharacteristicTEMP->createDescriptor(BLEUUID((uint16_t)0x2902));
    pNimBLEDescriptorTEMP->setValue("BME temperature Celsius");
    pCharacteristicTEMP->addDescriptor(pNimBLEDescriptorTEMP);

  #else
    pCharacteristicTEMP = pBmeService->createCharacteristic(TEMP_UUID, NIMBLE_PROPERTY::NOTIFY);

    NimBLEDescriptor* pNimBLEDescriptorTEMP = pCharacteristicTEMP->createDescriptor(BLEUUID((uint16_t)0x2902));
    pNimBLEDescriptorTEMP->setValue("BME temperature Fahrenheit");
    pCharacteristicTEMP->addDescriptor(pNimBLEDescriptorTEMP);
  #endif

How I have to implement this in NimBLE making a distinguish between these temperature scales?
Regards,
Jop

That's is not what the 2902 descriptor is for, it's only for setting the client notification subscription status.
You'll want to use some other method to achieve what you are doing here.


Add support for NFS shares

Ansible-NAS currently exports Samba shares, but some people live in a world of Linux machines and would rather work with NFS instead. An ansible thingie for that would make life easier. See https://advishnuprasad.com/blog/2016/03/29/setup-nfs-server-and-client-using-ansible/ for an example and https://help.ubuntu.com/community/SettingUpNFSHowTo for the background information.
(I dimly remember reading a recommendation that you shouldn't use the same directory/share for NFS and Samba because, uh, it was very bad and mice will eat your brain or something. Not sure if we should check for that?)

I've actually got a branch with this done on my desktop at home...Have deployed to my own Ansible-NAS and it seems to be working nicely. Just need to test a little more and will push soon 👍

I've just pushed #36268743776dbcdef02510f2994921402392fbf7 which includes NFS support. I've been using it myself for a bit and it seems OK - would appreciate some testing!


[Feature Request] Multiple values in single query

This query is incompatible with Boomtable:
SELECT non_negative_difference("read") AS "read", non_negative_difference("write") AS "write" FROM "disk" WHERE ("type" = 'disk_ops' A AND time >= now() - 5m GROUP BY "host",time(1m)"
The workaround is to use a single query for each column.

Yes. Boomtable doesn't support multiple values in single query. I can't implement this anytime soon as this require huge effort and design changes.

I think this has been fixed, because multiple values in one query works for me:
SELECT last("uptime") AS "last.m1.uptime", last("test") AS "last.m1.test" FROM "machines" WHERE ("id" = 'm1') AND time >= now() - 6h GROUP BY time(1m)

Glad to hear that you sorted out.

SELECT last("uptime") AS "last.m1.uptime", last("test") AS "last.m1.test" FROM "machines" WHERE ("id" = 'm1') AND time >= now() - 6h GROUP BY time(1m)

@florianwgnr  : I am curious to know how the dashboard looks with multiple values. care to share the dashboard screenshot ?
Regards,
Bala.

One select statement like this:
SELECT last("Demo 1") AS "[[templateVar]].Demo1", last("Demo 2") AS "[[templateVar]].Demo2", ...
and this is repeated for the template variables. Looks like this:


drop sbonazo el8 collection and add el9 appliance deps

Fixes #9
Fixes https://github.com/oVirt/ovirt-appliance/issues/25
Fixes issue # (delete if not relevant)
Changes introduced with this PR

Are you the owner of the code you are sending in, or do you have permission of the owner?
[y/n]

verified manually.  there's a python dep problem that needs to be fixed by centos


Cannot :confirm quit/bd/etc a terminal buffer

Describe the bug
Cannot :confirm quit/bd/etc a terminal window
To Reproduce
Detailed steps to reproduce the behavior:
vim --clean<cr>
:term<cr>
<c-\><c-n>:confirm quit<cr>

Current behaviour
Save changes to "!/bin/bash"?
When chosen 'yes': E676: No matching autocommands for acwrite buffer
When chosen 'no': Nothing happens
When chosen 'cancel': Nothing happens
Expected behaviour
When chosen 'yes': E382: Cannot write, 'buftype' option is set
When chosen 'no': Same behaviour as :quit!/bd!/etc!
When chosen 'cancel': Nothing happens
Environment (please complete the following information):

Vim version: 8.2.814

When using :confirm qa, Vim doesn't want to save but Vim wants to kill: Kill job in "!/bin/bash"? Answering 'yes' to that question does work.

Harm te Hennepe wrote:

Describe the bug
Cannot :confirm quit/bd/etc a terminal window
To Reproduce
Detailed steps to reproduce the behavior:
vim --clean<cr>
:term<cr>
<c-\><c-n>:confirm quit<cr>

Current behaviour
Save changes to "!/bin/bash"?
When chosen 'yes': E676: No matching autocommands for acwrite buffer

I suppose this should not really be an option.

When chosen 'no': Nothing happens

This should probably behave like "quit!".

When chosen 'cancel': Nothing happens

That's OK.

Expected behavior

The question should also be different, there is nothing to save.

When chosen 'yes': E382: Cannot write, 'buftype' option is set
When chosen 'no': Same behaviour as :quit!/bd!/etc!
When chosen 'cancel': Nothing happens
Environment (please complete the following information):

Vim version: 8.2.814

--
hundred-and-one symptoms of being an internet addict:
169. You hire a housekeeper for your home page.
/// Bram Moolenaar --<EMAIL_ADDRESS>-- http://www.Moolenaar.net   \
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \
\\  an exciting new programming language -- http://www.Zimbu.org        ///
\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

The question should also be different, there is nothing to save.

I think the 'Kill job' question would indeed be better, except for finished jobs.

I suppose the intended way to quit a terminal is Ctrl + D. Though I agree that converting to normal mode -> :confirm q should be able to work too, for consistency.


Refresh content after onclick event MF

Case:
Tab container holds multiple tabs containing the same datagrid snippet.
The datagrid retrieves data over association from a helper entity. The data should be refreshed each time a tab is being clicked. An onclick even within the tab container makes sure this data is being refreshed.
What I notice from the current widget, is that the data inside the tab is being refreshed before the onclick event completes. This causes the wrong data to be displayed.
I managed to fix my case by using xpath as a source for the datagrid, which solves this exact issue. But it would be a nice improvement to refresh the tab content after the onclick event has been completed (when set). Looks like it's running in parallel now.

Hi there,
I'm still trying to wrap my head around the problem. There isn't really an easy way for me to cache the content of each tab and one of the primary advantages of this widget over the Out-of-the-Box widget is it does not load all tabs at once.
If I added an option that would disable the tab changing on click of a tab and you have your on-click microflow change the Default Tab Index, would that solve your issue?

That should ensure that your on-click microflow finishes before the UI receives the new tab index and changes the content.

I've made a proof of concept into a prerelease. Please let me know if this helps.

Hi Benjamin,
That option would probably work!
It's not possible to disable the refresh of the content when a tab is clicked? That way you could refresh the content yourself within a darasource microflow or an on change event (?)

I've made a proof of concept into a prerelease. Please let me know if this helps.

Hi Benjamin, i'm not seeing any difference for this version and the latest release. Am i correct?

Hi there,
My bad, I uploaded the wrong file. If you download the file now from the GitHub prerelease, you should see a new option called "Disable tab change?".
Dynamic mode

Static mode

There isn't really a good way to block a tab refresh when switching tabs. This is because in my widget the content of other tabs is not rendered at all. When a tab is displayed, it creates that DOM from scratch. Unlike the out-of-the-box tab container which renders all tabs simultaneously and then hides the content of other tabs (leading to some performance issues depending on the use-case).

Hi Benjamin,
Your solution works great, i've tested the exact scenario using both a NF or MF for the change, activating the tab triggers the datasource MF on the new tab. 👍

Glad to hear! I've released version 1.2.0 to the Mendix Marketplace.
Please let me know if you encounter any other issues.


Standardized temperature units for LCN sensors

Use the standardized temperature units for Celsius and Fahrenheit for the LCN sensor compoenent.
Also the corresponding documentation has been updated.
Pull request in home-assistant.io with documentation (if applicable): home-assistant/home-assistant.io#8734
Checklist:

[x] The code change is tested and works locally.
[x] Local tests pass with tox. Your PR cannot be merged unless tests pass
[x] There is no commented out code in this PR.

If user exposed functionality or configuration variables are added/changed:

[x] Documentation added/updated in home-assistant.io

If the code communicates with devices, web services, or third-party tools:

[x] New dependencies have been added to the REQUIREMENTS variable (example).  - [ ] New dependencies are only imported inside functions that use them (example).
[x] New or updated dependencies have been added to requirements_all.txt by running script/gen_requirements_all.py.
[x] New files were added to .coveragerc.

Can be merged when build passes.


What is the reason to use GPL?

There are other Plan 9 systems under different licenses. We sought to have one under GPL, which is part of the purpose of the project. Does that answer your question? Maybe we can add that to the website. :)

which is part of the purpose of the project

what is the purpose? Does using an BSD/MIT/ISC license violets the purpose?

Sorry, I think we are heading a bit in a wrong direction. Let's start over. Could you elaborate on your question? I.e., do you seek to use Harvey for something that would violate the license?


Release/1.42.0

What
Release 1.42.0

[x] Update POST body dataset/{datasetId} to include type in Florence
[x] Previewing before save returns a 502 on edit metadata pages

How to review

Sense check
Trello tickets exist for the work
Make sure nothing has crept in that shouldn't be there

Who can review
Anyone but me

Hi, lots of those commits were already included in v1.41.0 release. You probably need rebase with master and only include relevant commits to this release :-)


Recorder: self-signed certificates don't work with Java 15+

see https://github.com/netty/netty/issues/10317
We need to load the BouncyCastle provider upfront

Fix no longer works because of the latest changes in Netty's SelfSignedCertificate


Refine the close triggers of the reporting date modal

The current behavior for the reporting date modal is to refresh the underlying list page only if one of the reporting period input fields was blank.  This was done to enable the user to enter indicators for the program.  This is already not ideal behavior, as it would be better to have the prompt change without a page refresh.
Now we are displaying a prompt to create additional target periods if the reporting end date is moved out far enough to no longer be covered by a reporting period.  If a user moves the reporting date out far enough that they should see this message, they shouldn't need to refresh the page for the message to appear.
The closing behavior of the reporting date modal should trigger the updates of the appropriate page elements without requiring a refresh.

As far as I can tell, there are three things that could be affected if the reporting end date is changed in the reporting date modal. 1) The region just below the Program name (indicator count, Indicator plan and Reporting period links), 2) The "Some indicators have missing targets..." text under the indicator count and 3) The "Missing targets" text just below the indicator name .
All of these sections are currently conditionally generated within the template (i.e. not by JS).  This means that updating them when the reporting date modal closes will require either a refresh (because the relevant elements have not been generated yet), generating all of them and then doing a show/hide where appropriate, or doing them in JS instead of the template.  Or some combination of those.  Another possibility that @jennyhavah  has mentioned might be to refresh the page but to have the same set of programs with expanded indicator sections as when the modal was opened.
@mahmoodkhan Is my assessment correct?  Do you have a suggestion about which approach or combo of approaches would be most appropriate?

@sanjuroj it is probably not a frequent event where program end dates are changed. I agree that it would be a nice enhancement to make but given the deadline for this release I think it wouldn't be unreasonable to reload the page and let the user expand to the appropriate section manually. If we do need to resolve this issue, then I think it might be simpler to reload the page and then expand the sections that were already expanded as @jennyhavah had mentioned. However, if the user has multiple sections expanded then would it still be helpful to expand all of the sections that were expanded?

@jennyhavah With the last update, the page will refresh if either reporting date is different from what was the value when the modal was opened. We talked about doing this as a safe place to start that would insure that the messaging on the the underlying indicator list page was updated if the reporting date was updated.
Additional changes to update the messaging without updating the whole page will take additional work.

@sanjuroj Though I don't know what's happening on the back end, the page doesn't appear to reload until I manually close the window by clicking the "x" or clicking outside the area. So I'm left thinking, "Now what"?
Would it be much extra work to have that particular modal reload and close when you click "Save changes"? (I know that's not how our Indicator setup modal behaves, but in that case you get lots of visual reinforcement by immediately seeing the effects of your changes on the Indicator rows. In the case of the Reporting period modal, it just looks like nothing happened.)

That should be pretty easy, I'll work on it.


sudo: a password is required

I'm using the user with paswordless sudo,
TASK [lablabs.rke2 : Replace loopback IP by master server IP] **********************************************************************************************************
fatal: [rke-test-3-dc3-mgmt -> localhost]: FAILED! => {"changed": false, "module_stderr": "sudo: a password is required\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}
fatal: [rke-test-1-dc1-mgmt -> localhost]: FAILED! => {"changed": false, "module_stderr": "sudo: a password is required\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

Hi @todeb thanks for this issue. The task which failed for you is running on local host. So, probably if you don't have passwordless sudo there, the task will fail with error you mentioned above.
However, there is no need to use privilege escalation on this task. I will fix it in next patch release.

What does this task is doing? Im also seeing that I do not have a kubeconfig copied to localhost. Maybe that is a reason.

This task replaces the localhost IP address by the IP address of the master server (or keepalived VIP) in the file ../../rke2.yaml .
In the release 1.2.0 the default path where the kubeconfig is downloaded is /tmp/rke2.yaml. You can specify custom path with variable rke2_download_kubeconf_path.

Closing due to inactivity.


Prepare 2.0.0-beta.12 release (Part 1)

Features Added

The library now includes support for the new OpenAI o1 model family.

ChatCompletionOptions will automatically apply its MaxOutputTokenCount value (renamed from MaxTokens) to the new max_completion_tokens request body property
Usage includes a new OutputTokenDetails property with a ReasoningTokenCount value that will reflect o1 model use of this new subcategory of output tokens.

Note that OutputTokenCount (completion_tokens) is the sum of displayed tokens generated by the model and (when applicable) these new reasoning tokens

Assistants file search now includes support for RankingOptions

Use of the include[] query string parameter and retrieval of run step detail result content is currently only available via protocol methods

Added support for the Uploads API in FileClient. This Experimental feature allows uploading large files in multiple parts.

The feature is supported by the CreateUpload, AddUploadPart, CompleteUpload, and CancelUpload protocol methods.

Breaking Changes

Renamed ChatMessageContentPart's CreateTextMessageContentPart factory method to CreateTextPart.
Renamed ChatMessageContentPart's CreateImageMessageContentPart factory method to CreateImagePart.
Renamed ChatMessageContentPart's CreateRefusalMessageContentPart factory method to CreateRefusalPart.
Renamed ImageChatMessageContentPartDetail to ChatImageDetailLevel.
Removed ChatMessageContentPart's ToString overload.
Renamed the MaxTokens property in ChatCompletionOptions to MaxOutputTokenCount
Renamed properties in ChatTokenUsage:

InputTokens is renamed to InputTokenCount
OutputTokens is renamed to OutputTokenCount
TotalTokens is renamed to TotalTokenCount

Removed the common ListOrder enum from the top-level OpenAI namespace in favor of individual enums in their corresponding sub-namespace.
Renamed the PageSize property to PageSizeLimit.
Updated deletion methods to return a result object instead of a bool. Affected methods:

DeleteAssitant, DeleteMessage, and DeleteThread in AssistantClient.
DeleteVectorStore and RemoveFileFromStore in VectorStoreClient.
DeleteModel in ModelClient.
DeleteFile in FileClient.

Removed setters from collection properties.
Renamed ChatTokenLogProbabilityInfo to ChatTokenLogProbabilityDetails.
Renamed ChatTokenTopLogProbabilityInfo to ChatTokenTopLogProbabilityDetails.
Renamed the Utf8ByteValues properties of ChatTokenLogProbabilityDetails and ChatTokenTopLogProbabilityDetails to Utf8Bytes and changed their type from IReadOnlyList<int> to ReadOnlyMemory<byte>?.
Renamed the Start and End properties of TranscribedSegment and TranscribedWord to StartTime and EndTime.
Changed the type of TranscribedSegment's AverageLogProbability and NoSpeechProbability properties from double to float.
Changed the type of TranscribedSegment's SeekOffset property from long to int.
Changed the type of TranscribedSegment's TokenIds property from IReadOnlyList<long> to IReadOnlyList<int>.
Updated the Embedding.Vector property to the Embedding.ToFloats() method.
Removed the optional parameter from the constructors of VectorStoreCreationHelper, AssistantChatMessage, and ChatFunction.
Removed the optional purpose parameter from FileClient.GetFilesAsync and FileClient.GetFiles methods, and added overloads where purpose is required.
Renamed ModerationClient's ClassifyTextInput methods to ClassifyText.
Removed duplicated Created property from GeneratedImageCollection.

Bugs Fixed

Addressed an issue that caused multi-page queries of fine-tuning jobs, checkpoints, and events to fail.
ChatCompletionOptions can now be serialized via ModelReaderWriter.Write() prior to calling CompleteChat using the options

Other Changes

Added support for CancellationToken to ModelClient methods.
Applied the Obsolete attribute where appropriate to align with the existing deprecations in the REST API.

@joseharriaga This part doesn't work in the latest beta nor the latest 2.1 release:

ChatCompletionOptions will automatically apply its MaxOutputTokenCount value (renamed from MaxTokens) to the new max_completion_tokens request body property

Using the o1-preview model paired with the latest API version, setting the MaxOutputTokenCount value errors out.

@bartczernicki Thank you for reaching out! By any chance, are you using the Azure OpenAI service and the Azure OpenAI companion library for .NET? I'm not able to reproduce the issue, and I'm wondering if the problem is related to Azure OpenAI or the companion library instead.
If you're using the Azure OpenAI companion library, could you file the issue in the Azure SDK repo here?
🔗 https://github.com/Azure/azure-sdk-for-net
If you can include some repro steps and/or code snippets, that would be super helpful. 🙂 Thanks!