qibolab.instruments package#

class qibolab.instruments.DummyLocalOscillator(*, address: str, settings: InstrumentSettings | None = None, device: Device | None = None, **extra_data: Any)[source]#

Bases: LocalOscillator

Dummy local oscillator instrument.

Useful for testing the interface defined in qibolab.instruments.oscillator.LocalOscillator.

create()[source]#

Create instance of physical device.

model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}#

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'allow', 'frozen': False}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'address': FieldInfo(annotation=str, required=True), 'device': FieldInfo(annotation=Union[Device, NoneType], required=False, default=None), 'settings': FieldInfo(annotation=Union[InstrumentSettings, NoneType], required=False, default_factory=<lambda>)}#

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

class qibolab.instruments.DummyInstrument(*, address: str, settings: InstrumentSettings | None = None, bounds: str = 'dummy/bounds', channels: dict[str, qibolab._core.components.channels.Channel] = None, **extra_data: Any)[source]#

Bases: Controller

Dummy instrument that returns random voltage values.

Useful for testing code without requiring access to hardware.

Parameters:
  • name (str) – name of the instrument.

  • address (int) – address to connect to the instrument. Not used since the instrument is dummy, it only exists to keep the same interface with other instruments.

address: str#
bounds: str#

Estimated limitations of the device memory.

channels: dict[str, qibolab._core.components.channels.Channel]#
property sampling_rate: int#

Sampling rate of control electronics in giga samples per second (GSps).

connect()[source]#

Establish connection to the physical instrument.

disconnect()[source]#

Close connection to the physical instrument.

values(options: ExecutionParameters, shape: tuple[int, ...])[source]#
play(configs: dict[str, qibolab._core.components.configs.Config], sequences: list[qibolab._core.sequence.PulseSequence], options: ExecutionParameters, sweepers: list[list[qibolab._core.sweeper.Sweeper]])[source]#

Play a pulse sequence and retrieve feedback.

If qibolab.Sweeper objects are passed as arguments, they are executed in real-time. If not possible, an error is raised.

Returns a mapping with the id of the probe pulses used to acquired data.

model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}#

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'allow', 'frozen': False}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'address': FieldInfo(annotation=str, required=True), 'bounds': FieldInfo(annotation=str, required=False, default='dummy/bounds'), 'channels': FieldInfo(annotation=dict[str, Channel], required=False, default_factory=dict), 'settings': FieldInfo(annotation=Union[InstrumentSettings, NoneType], required=False, default=None)}#

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

Submodules#

qibolab.instruments.bluefors module#

Bluefors drivers.

https://bluefors.com/

class qibolab.instruments.bluefors.TemperatureController(*, address: str, settings: InstrumentSettings | None = None, port: int = 8888, client_socket: socket = None, **extra_data: Any)[source]#

Bases: Instrument

Bluefors temperature controller.

Example usage:

if __name__ == "__main__":
    tc = TemperatureController("XLD1000_Temperature_Controller", "192.168.0.114", 8888)
    tc.connect()
    temperature_values = tc.read_data()
    for temperature_value in temperature_values:
        print(temperature_value)
address: str#

IP address of the board sending cryo temperature data.

port: int#

Port of the board sending cryo temperature data.

client_socket: socket#
connect()[source]#

Connect to the socket.

disconnect()[source]#

Disconnect from the socket.

get_data() dict[str, dict[str, float]][source]#

Connect to the socket and get temperature data.

The typical message looks like this:

flange_name: {'temperature':12.345678, 'timestamp':1234567890.123456}

timestamp can be converted to datetime using datetime.fromtimestamp.

Returns:

socket message in this format:

{“flange_name”: {‘temperature’: <value(float)>, ‘timestamp’:<value(float)>}}

Return type:

message (dict[str, dict[str, float]])

model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}#

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'allow', 'frozen': False}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'address': FieldInfo(annotation=str, required=True), 'client_socket': FieldInfo(annotation=socket, required=False, default_factory=<lambda>), 'port': FieldInfo(annotation=int, required=False, default=8888), 'settings': FieldInfo(annotation=Union[InstrumentSettings, NoneType], required=False, default=None)}#

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

model_post_init(context: Any, /) None#

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that’s what pydantic-core passes when calling it.

Parameters:
  • self – The BaseModel instance.

  • context – The context.

read_data()[source]#

Continously read data from the temperature controller.

qibolab.instruments.dummy module#

Dummy drivers.

Define instruments mainly used for testing purposes.

class qibolab.instruments.dummy.DummyLocalOscillator(*, address: str, settings: InstrumentSettings | None = None, device: Device | None = None, **extra_data: Any)[source]#

Bases: LocalOscillator

Dummy local oscillator instrument.

Useful for testing the interface defined in qibolab.instruments.oscillator.LocalOscillator.

create()[source]#

Create instance of physical device.

model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}#

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'allow', 'frozen': False}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'address': FieldInfo(annotation=str, required=True), 'device': FieldInfo(annotation=Union[Device, NoneType], required=False, default=None), 'settings': FieldInfo(annotation=Union[InstrumentSettings, NoneType], required=False, default_factory=<lambda>)}#

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

device: Device | None#
settings: InstrumentSettings | None#
address: str#
class qibolab.instruments.dummy.DummyInstrument(*, address: str, settings: InstrumentSettings | None = None, bounds: str = 'dummy/bounds', channels: dict[str, qibolab._core.components.channels.Channel] = None, **extra_data: Any)[source]#

Bases: Controller

Dummy instrument that returns random voltage values.

Useful for testing code without requiring access to hardware.

Parameters:
  • name (str) – name of the instrument.

  • address (int) – address to connect to the instrument. Not used since the instrument is dummy, it only exists to keep the same interface with other instruments.

address: str#
bounds: str#

Estimated limitations of the device memory.

channels: dict[str, qibolab._core.components.channels.Channel]#
property sampling_rate: int#

Sampling rate of control electronics in giga samples per second (GSps).

connect()[source]#

Establish connection to the physical instrument.

disconnect()[source]#

Close connection to the physical instrument.

values(options: ExecutionParameters, shape: tuple[int, ...])[source]#
play(configs: dict[str, qibolab._core.components.configs.Config], sequences: list[qibolab._core.sequence.PulseSequence], options: ExecutionParameters, sweepers: list[list[qibolab._core.sweeper.Sweeper]])[source]#

Play a pulse sequence and retrieve feedback.

If qibolab.Sweeper objects are passed as arguments, they are executed in real-time. If not possible, an error is raised.

Returns a mapping with the id of the probe pulses used to acquired data.

model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}#

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'allow', 'frozen': False}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'address': FieldInfo(annotation=str, required=True), 'bounds': FieldInfo(annotation=str, required=False, default='dummy/bounds'), 'channels': FieldInfo(annotation=dict[str, Channel], required=False, default_factory=dict), 'settings': FieldInfo(annotation=Union[InstrumentSettings, NoneType], required=False, default=None)}#

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

settings: InstrumentSettings | None#

qibolab.instruments.era module#

ERA drivers.

http://erainstruments.com/

class qibolab.instruments.era.ERASynth(address, ethernet=True, ref_osc_source=None)[source]#

Bases: LocalOscillator

Driver to control the ERAsynth++ local oscillator.

This driver is using: https://qcodes.github.io/Qcodes_contrib_drivers/api/generated/qcodes_contrib_drivers.drivers.ERAInstruments.html#qcodes_contrib_drivers.drivers.ERAInstruments.erasynth.ERASynthPlusPlus

or the custom qibolab.instruments.erasynth.ERASynthEthernet object if we are connected via ethernet.

model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}#

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'allow', 'frozen': False}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'address': FieldInfo(annotation=str, required=True), 'device': FieldInfo(annotation=Union[Device, NoneType], required=False, default=None), 'settings': FieldInfo(annotation=Union[InstrumentSettings, NoneType], required=False, default_factory=<lambda>)}#

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

create()[source]#

Create instance of physical device.

qibolab.instruments.qm module#

Quantum machines drivers.

https://quantum-machines.co/

class qibolab.instruments.qm.OpxOutputConfig(*, kind: Literal['opx-output'] = 'opx-output', offset: float = 0.0, filter: dict[str, list[float]] = None, output_mode: Literal['direct', 'amplified'] = 'direct')[source]#

Bases: DcConfig

DC channel config using QM OPX+.

kind: Literal['opx-output']#
offset: float#

DC offset to be applied in V.

Possible values are -0.5V to 0.5V.

filter: dict[str, list[float]]#

FIR and IIR filters to be applied for correcting signal distortions.

See https://docs.quantum-machines.co/1.1.7/qm-qua-sdk/docs/Guides/output_filter/?h=filter#output-filter for more details. Changing the filters affects the calibration of single shot discrimination (threshold and angle).

output_mode: Literal['direct', 'amplified']#
model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}#

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'filter': FieldInfo(annotation=dict[str, list[float]], required=False, default_factory=dict), 'kind': FieldInfo(annotation=Literal['opx-output'], required=False, default='opx-output'), 'offset': FieldInfo(annotation=float, required=False, default=0.0), 'output_mode': FieldInfo(annotation=Literal['direct', 'amplified'], required=False, default='direct')}#

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

class qibolab.instruments.qm.QmAcquisitionConfig(*, kind: Literal['qm-acquisition'] = 'qm-acquisition', delay: float, smearing: float, threshold: float | None = None, iq_angle: float | None = None, kernel: ndarray[Any, dtype[_ScalarType_co]] | None = None, gain: int = 0, offset: float = 0.0)[source]#

Bases: AcquisitionConfig

Acquisition config for QM OPX+.

kind: Literal['qm-acquisition']#
model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}#

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'delay': FieldInfo(annotation=float, required=True), 'gain': FieldInfo(annotation=int, required=False, default=0), 'iq_angle': FieldInfo(annotation=Union[float, NoneType], required=False, default=None), 'kernel': FieldInfo(annotation=Union[Annotated[ndarray[Any, dtype[+_ScalarType_co]], PlainValidator, PlainSerializer], NoneType], required=False, default=None, repr=False), 'kind': FieldInfo(annotation=Literal['qm-acquisition'], required=False, default='qm-acquisition'), 'offset': FieldInfo(annotation=float, required=False, default=0.0), 'smearing': FieldInfo(annotation=float, required=True), 'threshold': FieldInfo(annotation=Union[float, NoneType], required=False, default=None)}#

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

gain: int#

Input gain in dB.

Possible values are -12dB to 20dB in steps of 1dB.

offset: float#

Constant voltage to be applied on the input.

class qibolab.instruments.qm.OctaveOscillatorConfig(*, kind: Literal['octave-oscillator'] = 'octave-oscillator', frequency: float, power: float, output_mode: Literal['always_on', 'always_off', 'triggered', 'triggered_reversed'] = 'triggered')[source]#

Bases: OscillatorConfig

Oscillator confing that allows switching the output mode.

kind: Literal['octave-oscillator']#
output_mode: Literal['always_on', 'always_off', 'triggered', 'triggered_reversed']#
model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}#

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'frequency': FieldInfo(annotation=float, required=True), 'kind': FieldInfo(annotation=Literal['octave-oscillator'], required=False, default='octave-oscillator'), 'output_mode': FieldInfo(annotation=Literal['always_on', 'always_off', 'triggered', 'triggered_reversed'], required=False, default='triggered'), 'power': FieldInfo(annotation=float, required=True)}#

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

class qibolab.instruments.qm.QmController(*, address: str, settings: InstrumentSettings | None = None, bounds: str = 'qm/bounds', channels: dict[str, qibolab._core.components.channels.Channel] = None, octaves: dict[str, qibolab._core.instruments.qm.controller.Octave] = None, fems: dict[str, Literal['opx1', 'LF', 'MW']] = None, calibration_path: PathLike | None = None, write_calibration: bool = False, script_file_name: str | None = None, manager: QuantumMachinesManager | None = None, config: Configuration = None, simulation_duration: int | None = None, cloud: bool = False, **extra_data: Any)[source]#

Bases: Controller

qibolab.instruments.abstract.Controller object for controlling a Quantum Machines cluster.

Playing pulses on QM controllers requires a config dictionary and a program written in QUA language. The config file is generated using the dataclass objects defined in qibolab.instruments.qm.config. The QUA program is generated using the methods in qibolab.instruments.qm.program. Controllers, elements and pulses are added in the config after a pulse sequence is given, so that only elements related to the participating channels are registered.

address: str#

IP address and port for connecting to the OPX instruments.

Has the form XXX.XXX.XXX.XXX:XXX.

octaves: dict[str, qibolab._core.instruments.qm.controller.Octave]#

Dictionary containing the Octaves used.

fems: dict[str, Literal['opx1', 'LF', 'MW']]#

Dictionary containing the FEM types (for OPX1000 clusters).

Defaults to ‘opx1’ type to maintain original behavior for OPX+ clusters where fems are not given.

bounds: str#

Maximum bounds used for batching in sequence unrolling.

calibration_path: PathLike | None#

Path to the JSON file that contains the mixer calibration.

write_calibration: bool#

Require writing permissions on calibration DB.

script_file_name: str | None#

Name of the file that the QUA program will dumped in that after every execution.

If None the program will not be dumped.

manager: QuantumMachinesManager | None#

Manager object used for controlling the Quantum Machines cluster.

config: Configuration#

Configuration dictionary required for pulse execution on the OPXs.

simulation_duration: int | None#

Duration for the simulation in ns.

If given the simulator will be used instead of actual hardware execution.

cloud: bool#

If True the QM cloud simulator is used which does not require access to physical instruments.

This assumes that a proper cloud address has been given. If False and simulation_duration was given, then the built-in simulator of the instruments is used. This requires connection to instruments. Default is False.

model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}#

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'allow', 'frozen': False}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'address': FieldInfo(annotation=str, required=True), 'bounds': FieldInfo(annotation=str, required=False, default='qm/bounds'), 'calibration_path': FieldInfo(annotation=Union[PathLike, NoneType], required=False, default=None), 'channels': FieldInfo(annotation=dict[str, Channel], required=False, default_factory=dict), 'cloud': FieldInfo(annotation=bool, required=False, default=False), 'config': FieldInfo(annotation=Configuration, required=False, default_factory=Configuration), 'fems': FieldInfo(annotation=dict[str, Literal['opx1', 'LF', 'MW']], required=False, default_factory=<lambda>), 'manager': FieldInfo(annotation=Union[QuantumMachinesManager, NoneType], required=False, default=None), 'octaves': FieldInfo(annotation=dict[str, Octave], required=False, default_factory=dict), 'script_file_name': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'settings': FieldInfo(annotation=Union[InstrumentSettings, NoneType], required=False, default=None), 'simulation_duration': FieldInfo(annotation=Union[int, NoneType], required=False, default=None), 'write_calibration': FieldInfo(annotation=bool, required=False, default=False)}#

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

model_post_init(context: Any, /) None#

We need to both initialize private attributes and call the user-defined model_post_init method.

property sampling_rate#

Sampling rate of Quantum Machines instruments.

connect()[source]#

Connect to the Quantum Machines manager.

disconnect()[source]#

Disconnect from QM manager.

configure_device(device: str)[source]#

Add device in the config.

configure_channel(channel: str, configs: dict[str, qibolab._core.components.configs.Config]) str | None[source]#

Add element (QM version of channel) in the config.

When an AcquisitionChannel is registered it returns the corresponding probe channel in order to build an (acquisition, probe) map.

configure_channels(configs: dict[str, qibolab._core.components.configs.Config], channels: set[str]) dict[str, str][source]#

Register channels in the sequence in the QM config.

Builds a map from probe channels to the corresponding AcquisitionChannel. This is useful when sweeping frequency of probe channels, as these are registered as acquire elements in the QM config.

register_pulse(channel: str, config: Config, pulse: Pulse | Readout) str[source]#

Add pulse in the QM config.

And return corresponding operation.

register_pulses(configs: dict[str, qibolab._core.components.configs.Config], sequence: PulseSequence)[source]#

Adds all pulses except measurements of a given sequence in the QM config.

Returns:

Map from measurement instructions to acquisition objects.

Return type:

acquisitions (dict)

register_duration_sweeper_pulses(args: ExecutionArguments, configs: dict[str, qibolab._core.components.configs.Config], sweeper: Sweeper)[source]#

Register pulse with many different durations.

Needed when sweeping duration.

register_amplitude_sweeper_pulses(args: ExecutionArguments, configs: dict[str, qibolab._core.components.configs.Config], sweeper: Sweeper)[source]#

Register pulse with different amplitude.

Needed when sweeping amplitude because the original amplitude may not sufficient to reach all the sweeper values.

register_acquisitions(configs: dict[str, qibolab._core.components.configs.Config], sequence: PulseSequence, options: ExecutionParameters)[source]#

Add all measurements of a given sequence in the QM config.

Returns:

Map from measurement instructions to acquisition objects.

Return type:

acquisitions (dict)

preprocess_sweeps(sweepers: list[list[qibolab._core.sweeper.Sweeper]], configs: dict[str, qibolab._core.components.configs.Config], args: ExecutionArguments, probe_map: dict[str, str])[source]#

Preprocessing and checks needed before executing some sweeps.

Amplitude and duration sweeps require registering additional pulses in the QM ``config.

execute_program(program)[source]#

Executes an arbitrary program written in QUA language.

simulate_program(program)[source]#

Simulates an arbitrary program written in QUA language.

play(configs: dict[str, qibolab._core.components.configs.Config], sequences: list[qibolab._core.sequence.PulseSequence], options: ExecutionParameters, sweepers: list[list[qibolab._core.sweeper.Sweeper]])[source]#

Play a pulse sequence and retrieve feedback.

If qibolab.Sweeper objects are passed as arguments, they are executed in real-time. If not possible, an error is raised.

Returns a mapping with the id of the probe pulses used to acquired data.

class qibolab.instruments.qm.Octave(name: str, port: int, connectivity: str | tuple[str, int])[source]#

Bases: object

User-facing object for defining Octave configuration.

name: str#

Name of the device.

port: int#

Network port of the Octave in the cluster configuration.

connectivity: str | tuple[str, int]#

OPXplus that acts as the waveform generator for the Octave.

qibolab.instruments.rohde_schwarz module#

Rohde & Schwarz drivers.

https://www.rohde-schwarz.com/

class qibolab.instruments.rohde_schwarz.SGS100A(*, address: str, settings: InstrumentSettings | None = None, device: Device | None = None, **extra_data: Any)[source]#

Bases: LocalOscillator

Driver to control the Rohde-Schwarz SGS100A local oscillator.

This driver is using: https://qcodes.github.io/Qcodes/api/generated/qcodes.instrument_drivers.rohde_schwarz.html#module-qcodes.instrument_drivers.rohde_schwarz.SGS100A

create()[source]#

Create instance of physical device.

model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}#

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'allow', 'frozen': False}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'address': FieldInfo(annotation=str, required=True), 'device': FieldInfo(annotation=Union[Device, NoneType], required=False, default=None), 'settings': FieldInfo(annotation=Union[InstrumentSettings, NoneType], required=False, default_factory=<lambda>)}#

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.