Apply all the necessary transformations to the underlying dataclass so as to ensure it is fully type checked according to the rules in PEP 557.
(self)
| 229 | self._api = api |
| 230 | |
| 231 | def transform(self) -> bool: |
| 232 | """Apply all the necessary transformations to the underlying |
| 233 | dataclass so as to ensure it is fully type checked according |
| 234 | to the rules in PEP 557. |
| 235 | """ |
| 236 | info = self._cls.info |
| 237 | attributes = self.collect_attributes() |
| 238 | if attributes is None: |
| 239 | # Some definitions are not ready. We need another pass. |
| 240 | return False |
| 241 | for attr in attributes: |
| 242 | if attr.type is None: |
| 243 | return False |
| 244 | decorator_arguments = { |
| 245 | "init": self._get_bool_arg("init", True), |
| 246 | "eq": self._get_bool_arg("eq", self._spec.eq_default), |
| 247 | "order": self._get_bool_arg("order", self._spec.order_default), |
| 248 | "frozen": self._get_bool_arg("frozen", self._spec.frozen_default), |
| 249 | "slots": self._get_bool_arg("slots", False), |
| 250 | "match_args": self._get_bool_arg("match_args", True), |
| 251 | } |
| 252 | |
| 253 | # If there are no attributes, it may be that the semantic analyzer has not |
| 254 | # processed them yet. In order to work around this, we can simply skip generating |
| 255 | # __init__ if there are no attributes, because if the user truly did not define any, |
| 256 | # then the object default __init__ with an empty signature will be present anyway. |
| 257 | if ( |
| 258 | decorator_arguments["init"] |
| 259 | and ("__init__" not in info.names or info.names["__init__"].plugin_generated) |
| 260 | and attributes |
| 261 | ): |
| 262 | args = [ |
| 263 | attr.to_argument(info, of="__init__") |
| 264 | for attr in attributes |
| 265 | if attr.is_in_init and not self._is_kw_only_type(attr.type) |
| 266 | ] |
| 267 | |
| 268 | if info.fallback_to_any: |
| 269 | # Make positional args optional since we don't know their order. |
| 270 | # This will at least allow us to typecheck them if they are called |
| 271 | # as kwargs |
| 272 | for arg in args: |
| 273 | if arg.kind == ARG_POS: |
| 274 | arg.kind = ARG_OPT |
| 275 | |
| 276 | existing_args_names = {arg.variable.name for arg in args} |
| 277 | gen_args_name = "generated_args" |
| 278 | while gen_args_name in existing_args_names: |
| 279 | gen_args_name += "_" |
| 280 | gen_kwargs_name = "generated_kwargs" |
| 281 | while gen_kwargs_name in existing_args_names: |
| 282 | gen_kwargs_name += "_" |
| 283 | args = [ |
| 284 | Argument(Var(gen_args_name), AnyType(TypeOfAny.explicit), None, ARG_STAR), |
| 285 | *args, |
| 286 | Argument(Var(gen_kwargs_name), AnyType(TypeOfAny.explicit), None, ARG_STAR2), |
| 287 | ] |
| 288 |
no test coverage detected