> For clean Markdown content of this page, append .md to this URL. For the complete documentation index, see https://buildwithfern.com/learn/llms.txt. # Python configuration > Configuration options for the Fern Python SDK. You can customize the behavior of the Python SDK generator in `generators.yml`: **`generators.yml`** ```yaml {6-16} title="generators.yml" groups: python-sdk: generators: - name: fern-python version: 5.31.0 config: package_name: "your_package" client: class_name: "YourClient" additional_init_exports: - from: file_with_custom_function imports: - custom_function pydantic_config: skip_validation: true environment_class_name: "AcmeEnvironment" ``` **`additional_init_exports`** `array of objects` — default: null Additional modules or classes to export from the package's `__init__.py` file. This allows you to customize what's available when users import your package. Each object should specify which file to import from and what to import: ```yaml config: additional_init_exports: - from: core.oauth_flow imports: - validate_token - from: utils.helpers imports: - format_currency - PhoneValidator ``` This enables users to access your custom functions directly: ```python from my_package import validate_token, format_currency, PhoneValidator ``` --- **`additional_init_exports[].from`** `string` — required The module path to import from, using Python dot notation. Omit the `.py` extension and replace path separators with dots. For example, if you want to import from the file `core/oauth_flow.py`, specify that as `- from: core.oauth_flow`. --- **`additional_init_exports[].imports`** `array of strings` — required List of class names, function names, or other objects to import from the specified file. --- **`auto-generate-idempotency-key`** `boolean | object` — default: false Overrides the API-wide [`api.settings.auto-generate-idempotency-key`](/learn/sdks/reference/generators-yml#settings) for this SDK. Set `true` to attach an [idempotency-key header](/learn/sdks/deep-dives/idempotency#auto-generate-idempotency-keys) to eligible requests (`POST` and `PUT` by default) unless the caller provides one, or `false` to opt this SDK out when auto-generation is enabled API-wide. Pass an object to customize `header-name` and `methods`. --- **`client_class_name`** `string` — deprecated, default: null Deprecated. Use [`client.class_name`](#client) instead. Sets the name of the generated client class; must be PascalCase. For example, `client_class_name: "Acme"` generates a client that users import as `from your_package import Acme`. If both `client_class_name` and `client.class_name` are set, `client_class_name` takes precedence. --- **`default_bytes_stream_chunk_size`** `number` — default: null The chunk size to use (if any) when processing a response bytes stream within `iter_bytes` or `aiter_bytes` results in: `for chunk in response.iter_bytes(chunk_size=):` --- **`default_max_retries`** `number` — default: 2 The default number of retries for failed requests in the generated SDK. Set to `0` to disable retries by default. SDK users can still override this per-request via request options. --- **`encode_path_params`** `bool` — default: false Percent-encodes path parameter values when the generated SDK substitutes them into the request path. By default, values are inserted unencoded, so a value containing `/` or `..` changes the path the request resolves to: for an endpoint `GET /plants/{plantId}`, a `plantId` of `../plants` requests `/plants`. When enabled, the same value requests `/plants/..%2Fplants`. --- **`enable_wire_tests`** `bool` — default: false When enabled, generates [mock server (wire) tests](/learn/sdks/deep-dives/testing#mock-server-tests) to verify that the SDK sends and receives HTTP requests as expected. --- **`exclude_types_from_init_exports`** `boolean` — default: false When enabled, excludes type definitions from being exported in the package's `__init__.py` file, reducing the public API surface. --- **`environment_class_name`** `string` — default: \{ClientName}Environment Customize the name of the generated environment class/enum. By default, the environment class is named `{ClientName}Environment` (e.g., `AcmeEnvironment` for a client named `Acme`). --- **`extra_dependencies`** `object` — default: \{} #### Enterprise feature This feature is available only for the [Enterprise plan](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). If you want to add custom dependencies to your generated SDK, you can specify them using this configuration. For example, to add a dependency on boto3, your config would look like: ```yaml config: extra_dependencies: boto3: 1.28.15 ``` --- **`extra_dev_dependencies`** `object` — default: \{} #### Enterprise feature This feature is available only for the [Enterprise plan](https://buildwithfern.com/pricing). To get started, reach out to [support@buildwithfern.com](mailto:support@buildwithfern.com). Specify additional development dependencies to include in the generated SDK's setup configuration. These are dependencies used for development and testing but not required by end users. --- **`extras`** `object` — default: \{} Define optional dependency groups that users can install with your package using pip extras (e.g., `pip install your-package[extra-name]`). Custom extras are merged with the built-in [`aiohttp` extra](/learn/sdks/generators/python/aiohttp-support) at generation time, so declaring your own extras won't clobber it. --- **`flat_layout`** `bool` — default: false When enabled, generates a flatter package structure by reducing nested directories and modules. --- **`follow_redirects_by_default`** `bool` — default: true Whether to follow redirects by default in HTTP requests. --- **`improved_imports`** `bool` — default: true Feature flag that improves imports in the Python SDK by removing nested `resources` directory --- **`import_paths`** `array of strings` — default: null Paths to files that are automatically imported when the SDK package is loaded. This is useful for running custom setup code, such as Sentry integration, logging configuration, or telemetry hooks without modifying generated code. Each entry is a module name relative to the package root (omit the `.py` extension). The SDK will attempt to import each module at package initialization time; missing files are skipped. ```yaml config: import_paths: - sentry_integration - custom_logging ``` Files listed in `import_paths` must also be added to `.fernignore` so they're not overwritten during generation. --- **`include_legacy_wire_tests`** `bool` — default: false Whether or not to include legacy wire tests in the generated SDK --- **`include_union_utils`** `bool` — default: false When enabled, generates utility methods for working with union types, including factory methods and visitor patterns. --- **`inline_path_params`** `bool` — default: false If true, treats path parameters as named parameters in endpoint functions. --- **`inline_request_params`** `bool` — default: true Feature flag that removes the usage of request objects, and instead uses parameters in function signatures where possible. --- **`lazy_imports`** `bool` — default: true Enables lazy loading of client imports. When enabled, modules and classes are imported only when first accessed rather than at package initialization. This reduces memory footprint when using a small portion of a large API, at the cost of a latency penalty when first accessing a client. Set to `false` to restore eager loading behavior. --- **`license_header`** `string` — default: null Text to emit as a comment block at the top of every generated Python file, including each `__init__.py`, above the auto-generated notice. Lines that already start with `#` are passed through verbatim. ```yaml config: license_header: | Copyright 2026 Plant Store, Inc. Licensed under the Apache License, Version 2.0. ``` Each generated file then starts with: ```python # Copyright 2026 Plant Store, Inc. # Licensed under the Apache License, Version 2.0. # This file was auto-generated by Fern from our API Definition. ``` --- **`package_name`** `string` — default: null Specifies the Python package name that users will import your generated client from. For example, setting `package_name: "my_custom_package"` enables users to use `my_custom_package import Client` to import your client. --- **`offset_semantics`** `'item-index' | 'page-index'` — default: item-index Controls how the offset parameter is interpreted for [auto-paginated](/learn/sdks/deep-dives/auto-pagination) endpoints. * `item-index`: The offset counts individual items (e.g., offset 20 skips the first 20 items). * `page-index`: The offset counts pages (e.g., offset 3 skips to page 3). --- **`omit_fern_headers`** `bool` — default: false When enabled, the generated SDK omits the `X-Fern-Language`, `X-Fern-SDK-Name`, and `X-Fern-SDK-Version` headers from HTTP requests. To keep the headers but have the reported version track the installed package rather than the generation-time version, use [`runtime_version`](#runtime_version). --- **`include_platform_headers`** `bool` — default: false When enabled, the generated SDK sends a single structured `User-Agent` header of the form `{sdkName}/{version} ({os}; {arch}) {runtime}/{runtimeVersion}` (for example, `fern_examples/0.0.1 (linux; x86_64) Python/3.11.0`), carrying SDK, operating system, architecture, and runtime information in place of the default `User-Agent` and discrete platform headers. A configured [`user-agent`](#user-agent) template supplies the leading product token. If `omit_fern_headers` is enabled, no `User-Agent` or platform headers are sent and this option has no effect. --- **`allow_user_agent_app_info`** `bool` — default: false When enabled, the generated client constructor accepts `app_info: typing.Optional[typing.Dict[str, str]] = None`, which appends a `{name}/{version} ({comment})` [product token](https://www.rfc-editor.org/rfc/rfc9110#name-user-agent) to the `User-Agent` header so an application built on the SDK can identify itself to the API. The application passes a required `name` key plus optional `version` and `comment` keys; omitted or blank values are dropped from the token. An explicit `User-Agent` header takes precedence, and [`omit_fern_headers`](#omit_fern_headers) suppresses the header entirely. ```python app_info={"name": "partner-app", "version": "3.1.0", "comment": "+https://partner.example"} # User-Agent: fern_examples/0.0.1 (linux; x86_64) Python/3.11.0 partner-app/3.1.0 (+https://partner.example) ``` --- **`optional_auth`** `bool` — default: false When enabled, client auth parameters (bearer token, basic auth username and password, header auth) remain optional even when the spec's [security requirements](/learn/api-definitions/openapi/authentication) mandate auth on every endpoint, and requests are sent without an auth header when no credential is provided. By default, the client raises an error when a mandatory credential is missing. Also accepted as `optional-auth` or `optionalAuth`. Enable this when callers authenticate through a mechanism other than the API's own scheme, such as cloud provider credentials, and would otherwise have to pass a placeholder value. --- **`pyproject_python_version`** `string` — default: ^3.10 This changes your declared python dependency, which is not meant to be done often if at all. This is a last resort if any dependencies force you to change your version requirements. --- **`pyproject_toml`** `string` — default: null Allow specifying arbitrary configuration to your packages `pyproject.toml` by adding a `pyproject_toml` block to your configuration whatever you include in this block will be added as-is to the `pyproject.toml` file. The config, as an example is: ```yaml config: pyproject_toml: | [tool.covcheck.group.unit.coverage] branch = 26.0 line = 62.0 [tool.covcheck.group.service.coverage] branch = 30.0 line = 67.0 ``` --- **`respect_optional_request_body`** `bool` — default: false Lets callers omit the request body on endpoints with an optional request body. A call that omits it sends no body and no `Content-Type` header, instead of an empty JSON object (`{}`). Enable this when your API treats a missing body differently from an empty one. The parameter defaults to the `OMIT` sentinel, so an explicit `None` stays distinguishable from a body that was never passed: ```python def water_plant(self, plant_id: str, *, request: WaterRequest = OMIT, ...) ``` Only applies to request bodies declared as a single named type. Required bodies and inlined request properties are unaffected. --- **`runtime_version`** `bool` — default: false When enabled, the generated SDK resolves the version it reports in the `X-Fern-SDK-Version` header and the [structured `User-Agent`](#include_platform_headers) version segment at runtime with `importlib.metadata.version()`, instead of the version baked in at generation time. Enable this when external release tooling determines the published version after generation, so the reported version always matches the installed package. The generation-time version is used as a fallback when the distribution isn't installed. If [`omit_fern_headers`](#omit_fern_headers) is enabled, the SDK reports no version at all and this option has no effect. --- **`should_generate_websocket_clients`** `bool` — default: false Enable generation of Python [WebSocket clients](/learn/sdks/deep-dives/websocket-clients). --- **`skip_formatting`** `bool` — default: false When enabled, skips code formatting (like black) on the generated Python code. --- **`stream_abstraction`** `bool` — default: false When enabled, streaming endpoints return a `Stream[T]` (`AsyncStream[T]` for async clients) instead of a generator. Iterating yields the parsed payloads; `with_metadata()` yields them wrapped with the [server-sent event metadata](/learn/sdks/deep-dives/sse-metadata) fields `id`, `event`, and `retry`. ```python for event in client.plants.stream(query="fern").with_metadata(): print(event.id, event.data) ``` This option changes the return type of streaming methods, so it remains opt-in until the next major generator version. --- **`timeout`** `number | 'infinity'` — default: 60 Sets the client timeout in seconds, or `infinity` to disable timeouts. --- **`user-agent`** `string` — default: \{packageName}/\{version} Sets a custom `User-Agent` header template for requests sent by the generated SDK. The template is resolved at generation time and supports the `{packageName}`, `{version}`, `{language}`, `{generatorVersion}`, `{organization}`, and `{apiName}` placeholders. **`generators.yml`** ```yaml title="generators.yml" config: user-agent: "plantstore-python-sdk/{version}" ``` This sends `User-Agent: plantstore-python-sdk/0.1.0`. With [`include_platform_headers`](#include_platform_headers) enabled, the resolved value leads the structured header: `User-Agent: plantstore-python-sdk/0.1.0 (linux; x86_64) Python/3.11.0`. A value that doesn't end in a version, such as `plantstore/sdk-python`, is used as-is. The [`allow_user_agent_app_info`](#allow_user_agent_app_info) token is appended after either form, and [`runtime_version`](#runtime_version) replaces the trailing version segment at runtime. --- **`use_api_name_in_package`** `bool` — default: false When enabled, includes the API name as part of the package structure and naming. --- **`use_inheritance_for_extended_models`** `bool` — default: true Whether to generate Pydantic models that implement inheritance when a model utilizes the Fern `extends` keyword. --- **`use_typeddict_requests`** `bool` — default: false Whether or not to generate `TypedDicts` instead of Pydantic Models for request objects. --- **`use_typeddict_requests_for_file_upload`** `bool` — default: false Whether or not to generate TypedDicts instead of Pydantic Models for file upload request objects. Note that this flag was only introduced due to an oversight in the `use_typeddict_requests` flag implementation; it should be removed in the future. --- ### client The `client` block configures the generated client class and file structure. It replaces the deprecated top-level `client_class_name` and `client_filename` options. Use `exported_class_name` and `exported_filename` when the internal and exported class names differ. ```yaml config: client: filename: "my_client.py" class_name: "MyClient" exported_filename: "my_client.py" exported_class_name: "MyClient" ``` **`client.filename`** `string` — default: client.py The filename for the generated client file. --- **`client.class_name`** `string` — default: null The name of the generated client class. Must be PascalCase. For example, `class_name: "Acme"` generates a client that users import as `from your_package import Acme`. --- **`client.exported_filename`** `string` — default: client.py The filename of the exported client which will be used in code snippets. --- **`client.exported_class_name`** `string` — default: null The name of the exported client class that will be used in code snippets. --- ### pydantic\_config Configure Pydantic model generation settings for your Python SDK. ```yaml config: pydantic_config: enum_type: "literals" extra_fields: "forbid" frozen: true include_union_utils: false include_validators: true orm_mode: false positional_single_property_constructors: false require_optional_fields: false skip_formatting: false skip_validation: true smart_union: true union_naming: "v0" use_inheritance_for_extended_models: true use_pydantic_field_aliases: false use_provided_defaults: true use_str_enums: true use_typeddict_requests: false wrapped_aliases: false ``` **`enum_type`** `'literals' | 'forward_compatible_python_enums' | 'python_enums'` — default: literals The type of enums to use in the generated models: * `literals`: Use Python Literal types, e.g. `MyEnum = Literal["foo", "bar"]` * `forward_compatible_python_enums`: Use Python Enum classes, with a `MyEnum._UNKNOWN` member for forward compatibility. `MyEnum._UNKNOWN.value` contains the raw unrecognized value. * `python_enums`: Your vanilla Python enum class, with the members defined within your API. --- **`extra_fields`** `literal<'allow' | 'forbid' | 'ignore'>` — default: allow How to handle extra fields not defined in the model schema. --- **`frozen`** `bool` — default: true Whether Pydantic models should be frozen (immutable after creation). --- **`include_union_utils`** `bool` — default: false When enabled, the generator will output a Pydantic `__root__` class that will contain utilities to visit the union. For example, for the following union type: ``` types: Shape: union: circle: Circle triangle: Triangle ``` you will get a generated `Shape` class that has a factory and visitor: ```python # Use a factory to instantiate the union Shape.factory.circle(Circle(...)) # Visit every case in the union shape = get_shape() shape.visit( circle: lambda circle: do_something_with_circle(circle), triangle: lambda triangle: do_something_with_triangle(triangle), ) ``` --- **`include_validators`** `bool` — default: false Include custom validators in generated Pydantic models. --- **`orm_mode`** `bool` — default: false Enable ORM mode for Pydantic models to work with ORMs like SQLAlchemy. --- **`positional_single_property_constructors`** `bool` — default: false When enabled, generates a custom `__init__` method for models with a single required field, allowing positional argument construction instead of requiring keyword arguments. ```python # Without positional_single_property_constructors (default) wrapper = Wrapper(value="my_value") # With positional_single_property_constructors enabled wrapper = Wrapper("my_value") ``` Enabling this option can cause backwards compatibility issues. If a model later adds another required field, the positional `__init__` will no longer be generated, causing runtime failures for existing code that uses positional arguments. Use keyword arguments for long-term stability. --- **`package_name`** `string` Custom package name for the generated models. --- **`require_optional_fields`** `bool` — default: false Whether optional fields must be explicitly provided (cannot be omitted). --- **`skip_formatting`** `bool` — default: false Skip code formatting for generated Pydantic models. --- **`skip_validation`** `bool` — default: false When enabled, disables Pydantic validation for API responses. This ensures that Pydantic does not immediately fail if the model being returned from an API does not exactly match the Pydantic model. This is meant to add flexibility should your SDK fall behind your API, but should be used sparingly, as the type-hinting for users will still reflect the Pydantic model exactly. --- **`smart_union`** `bool` — default: true Enable smart union handling in Pydantic models for better type discrimination. --- **`union_naming`** `'v0' | 'v1'` — default: v0 Control union naming strategy. If you are dealing with discriminated union members that already have the discriminant property on them (and they're only used in one union), you should prefer the global API config within your `generators.yml`: ```yaml - name: fern-python-sdk version: 3.0.0-rc0 api: settings: unions: v1 ``` --- **`use_pydantic_field_aliases`** `bool` — default: false Use Pydantic field aliases for property names that differ from wire format. --- **`use_provided_defaults`** `bool` — default: false Leverage defaults specified in the API specification. --- **`use_typeddict_requests`** `bool` — default: false Generate TypedDicts instead of Pydantic Models for request objects. --- **`version`** `'v1' | 'v2' | 'both' | 'v1_on_v2'` — default: both By default, the generator generates pydantic models that are v1 and v2 compatible. However you can override them to: * `v1`: strictly use Pydantic v1 * `v2`: strictly use Pydantic v2 * `both`: maintain compatibility with both versions * `v1_on_v2`: use Pydantic v1 compatibility layer on v2 --- **`wrapped_aliases`** `bool` — default: false Enable wrapped aliases for Pydantic models. Only supported in Pydantic V1, V1\_ON\_V2, or V2. --- **`use_inheritance_for_extended_models`** `bool` — default: true Generate Pydantic models that implement inheritance when a model utilizes the Fern `extends` keyword. --- > Configuration options for the Fern Python SDK.