@@ -266,6 +266,11 @@ def client_networks_create(self, name: str, param: dict[str, Any]) -> "DockerNet
266266 labels = create_labels ("" , param .get ("labels" ))
267267 return self .client .networks .create (name , ** {** param , "labels" : labels })
268268
269+ def get_container_inspect_info (self , container_id : str ) -> "ContainerInspectInfo" :
270+ """Get container inspect information with fresh data."""
271+ container = self .client .containers .get (container_id )
272+ return ContainerInspectInfo .from_dict (container .attrs )
273+
269274
270275def get_docker_host () -> Optional [str ]:
271276 return c .tc_properties_get_tc_host () or os .getenv ("DOCKER_HOST" )
@@ -542,6 +547,44 @@ class ContainerHostConfig:
542547 MaskedPaths : Optional [list [str ]] = None
543548 ReadonlyPaths : Optional [list [str ]] = None
544549
550+ def __post_init__ (self ) -> None :
551+ list_conversions = [
552+ ("BlkioWeightDevice" , ContainerBlkioWeightDevice ),
553+ ("BlkioDeviceReadBps" , ContainerBlkioDeviceRate ),
554+ ("BlkioDeviceWriteBps" , ContainerBlkioDeviceRate ),
555+ ("BlkioDeviceReadIOps" , ContainerBlkioDeviceRate ),
556+ ("BlkioDeviceWriteIOps" , ContainerBlkioDeviceRate ),
557+ ("Devices" , ContainerDeviceMapping ),
558+ ("DeviceRequests" , ContainerDeviceRequest ),
559+ ("Ulimits" , ContainerUlimit ),
560+ ("Mounts" , ContainerMountPoint ),
561+ ]
562+
563+ for field_name , target_class in list_conversions :
564+ field_value = getattr (self , field_name )
565+ if field_value is not None and isinstance (field_value , list ):
566+ setattr (
567+ self ,
568+ field_name ,
569+ [
570+ _ignore_properties (target_class , item ) if isinstance (item , dict ) else item
571+ for item in field_value
572+ ],
573+ )
574+
575+ if self .LogConfig is not None and isinstance (self .LogConfig , dict ):
576+ self .LogConfig = _ignore_properties (ContainerLogConfig , self .LogConfig )
577+
578+ if self .RestartPolicy is not None and isinstance (self .RestartPolicy , dict ):
579+ self .RestartPolicy = _ignore_properties (ContainerRestartPolicy , self .RestartPolicy )
580+
581+ if self .PortBindings is not None and isinstance (self .PortBindings , dict ):
582+ for port , bindings in self .PortBindings .items ():
583+ if bindings is not None and isinstance (bindings , list ):
584+ self .PortBindings [port ] = [
585+ _ignore_properties (ContainerPortBinding , b ) if isinstance (b , dict ) else b for b in bindings
586+ ]
587+
545588
546589@dataclass
547590class ContainerGraphDriver :
@@ -669,6 +712,31 @@ class ContainerNetworkSettings:
669712 MacAddress : Optional [str ] = None
670713 Networks : Optional [dict [str , ContainerNetworkEndpoint ]] = None
671714
715+ def __post_init__ (self ) -> None :
716+ if self .Ports is not None and isinstance (self .Ports , dict ):
717+ for port , bindings in self .Ports .items ():
718+ if bindings is not None and isinstance (bindings , list ):
719+ self .Ports [port ] = [
720+ _ignore_properties (ContainerPortBinding , b ) if isinstance (b , dict ) else b for b in bindings
721+ ]
722+
723+ if self .Networks is not None and isinstance (self .Networks , dict ):
724+ for name , network_data in self .Networks .items ():
725+ if isinstance (network_data , dict ):
726+ self .Networks [name ] = _ignore_properties (ContainerNetworkEndpoint , network_data )
727+
728+ if self .SecondaryIPAddresses is not None and isinstance (self .SecondaryIPAddresses , list ):
729+ self .SecondaryIPAddresses = [
730+ _ignore_properties (ContainerAddress , addr ) if isinstance (addr , dict ) else addr
731+ for addr in self .SecondaryIPAddresses
732+ ]
733+
734+ if self .SecondaryIPv6Addresses is not None and isinstance (self .SecondaryIPv6Addresses , list ):
735+ self .SecondaryIPv6Addresses = [
736+ _ignore_properties (ContainerAddress , addr ) if isinstance (addr , dict ) else addr
737+ for addr in self .SecondaryIPv6Addresses
738+ ]
739+
672740 def get_networks (self ) -> Optional [dict [str , ContainerNetworkEndpoint ]]:
673741 """Get networks for the container."""
674742 return self .Networks
@@ -730,15 +798,17 @@ def from_dict(cls, data: dict[str, Any]) -> "ContainerInspectInfo":
730798 ProcessLabel = data .get ("ProcessLabel" ),
731799 AppArmorProfile = data .get ("AppArmorProfile" ),
732800 ExecIDs = data .get ("ExecIDs" ),
733- HostConfig = cls ._parse_host_config (data .get ("HostConfig" , {})) if data .get ("HostConfig" ) else None ,
801+ HostConfig = _ignore_properties (ContainerHostConfig , data .get ("HostConfig" , {}))
802+ if data .get ("HostConfig" )
803+ else None ,
734804 GraphDriver = _ignore_properties (ContainerGraphDriver , data .get ("GraphDriver" , {}))
735805 if data .get ("GraphDriver" )
736806 else None ,
737807 SizeRw = data .get ("SizeRw" ),
738808 SizeRootFs = data .get ("SizeRootFs" ),
739809 Mounts = [_ignore_properties (ContainerMount , mount ) for mount in data .get ("Mounts" , [])],
740810 Config = _ignore_properties (ContainerConfig , data .get ("Config" , {})) if data .get ("Config" ) else None ,
741- NetworkSettings = cls . _parse_network_settings ( data .get ("NetworkSettings" , {}))
811+ NetworkSettings = _ignore_properties ( ContainerNetworkSettings , data .get ("NetworkSettings" , {}))
742812 if data .get ("NetworkSettings" )
743813 else None ,
744814 )
@@ -799,164 +869,14 @@ def _parse_host_config(cls, data: dict[str, Any]) -> Optional[ContainerHostConfi
799869 """Parse HostConfig with all nested objects."""
800870 if not data :
801871 return None
802-
803- blkio_weight_devices = [
804- _ignore_properties (ContainerBlkioWeightDevice , d ) for d in (data .get ("BlkioWeightDevice" ) or [])
805- ]
806- blkio_read_bps = [
807- _ignore_properties (ContainerBlkioDeviceRate , d ) for d in (data .get ("BlkioDeviceReadBps" ) or [])
808- ]
809- blkio_write_bps = [
810- _ignore_properties (ContainerBlkioDeviceRate , d ) for d in (data .get ("BlkioDeviceWriteBps" ) or [])
811- ]
812- blkio_read_iops = [
813- _ignore_properties (ContainerBlkioDeviceRate , d ) for d in (data .get ("BlkioDeviceReadIOps" ) or [])
814- ]
815- blkio_write_iops = [
816- _ignore_properties (ContainerBlkioDeviceRate , d ) for d in (data .get ("BlkioDeviceWriteIOps" ) or [])
817- ]
818- devices = [_ignore_properties (ContainerDeviceMapping , d ) for d in (data .get ("Devices" ) or [])]
819- device_requests = [_ignore_properties (ContainerDeviceRequest , d ) for d in (data .get ("DeviceRequests" ) or [])]
820- ulimits = [_ignore_properties (ContainerUlimit , d ) for d in (data .get ("Ulimits" ) or [])]
821- mounts = [_ignore_properties (ContainerMountPoint , d ) for d in (data .get ("Mounts" ) or [])]
822-
823- port_bindings : dict [str , Optional [list [ContainerPortBinding ]]] = {}
824- port_bindings_data = data .get ("PortBindings" )
825- if port_bindings_data is not None :
826- for port , bindings in port_bindings_data .items ():
827- if bindings is None :
828- port_bindings [port ] = None
829- else :
830- port_bindings [port ] = [_ignore_properties (ContainerPortBinding , b ) for b in bindings ]
831-
832- return ContainerHostConfig (
833- CpuShares = data .get ("CpuShares" ),
834- Memory = data .get ("Memory" ),
835- CgroupParent = data .get ("CgroupParent" ),
836- BlkioWeight = data .get ("BlkioWeight" ),
837- BlkioWeightDevice = blkio_weight_devices if blkio_weight_devices else None ,
838- BlkioDeviceReadBps = blkio_read_bps if blkio_read_bps else None ,
839- BlkioDeviceWriteBps = blkio_write_bps if blkio_write_bps else None ,
840- BlkioDeviceReadIOps = blkio_read_iops if blkio_read_iops else None ,
841- BlkioDeviceWriteIOps = blkio_write_iops if blkio_write_iops else None ,
842- CpuPeriod = data .get ("CpuPeriod" ),
843- CpuQuota = data .get ("CpuQuota" ),
844- CpuRealtimePeriod = data .get ("CpuRealtimePeriod" ),
845- CpuRealtimeRuntime = data .get ("CpuRealtimeRuntime" ),
846- CpusetCpus = data .get ("CpusetCpus" ),
847- CpusetMems = data .get ("CpusetMems" ),
848- Devices = devices if devices else None ,
849- DeviceCgroupRules = data .get ("DeviceCgroupRules" ),
850- DeviceRequests = device_requests if device_requests else None ,
851- KernelMemoryTCP = data .get ("KernelMemoryTCP" ),
852- MemoryReservation = data .get ("MemoryReservation" ),
853- MemorySwap = data .get ("MemorySwap" ),
854- MemorySwappiness = data .get ("MemorySwappiness" ),
855- NanoCpus = data .get ("NanoCpus" ),
856- OomKillDisable = data .get ("OomKillDisable" ),
857- Init = data .get ("Init" ),
858- PidsLimit = data .get ("PidsLimit" ),
859- Ulimits = ulimits if ulimits else None ,
860- CpuCount = data .get ("CpuCount" ),
861- CpuPercent = data .get ("CpuPercent" ),
862- IOMaximumIOps = data .get ("IOMaximumIOps" ),
863- IOMaximumBandwidth = data .get ("IOMaximumBandwidth" ),
864- Binds = data .get ("Binds" ),
865- ContainerIDFile = data .get ("ContainerIDFile" ),
866- LogConfig = _ignore_properties (ContainerLogConfig , data .get ("LogConfig" , {}))
867- if data .get ("LogConfig" )
868- else None ,
869- NetworkMode = data .get ("NetworkMode" ),
870- PortBindings = port_bindings if port_bindings else None ,
871- RestartPolicy = _ignore_properties (ContainerRestartPolicy , data .get ("RestartPolicy" , {}))
872- if data .get ("RestartPolicy" )
873- else None ,
874- AutoRemove = data .get ("AutoRemove" ),
875- VolumeDriver = data .get ("VolumeDriver" ),
876- VolumesFrom = data .get ("VolumesFrom" ),
877- Mounts = mounts if mounts else None ,
878- ConsoleSize = data .get ("ConsoleSize" ),
879- Annotations = data .get ("Annotations" ),
880- CapAdd = data .get ("CapAdd" ),
881- CapDrop = data .get ("CapDrop" ),
882- CgroupnsMode = data .get ("CgroupnsMode" ),
883- Dns = data .get ("Dns" ),
884- DnsOptions = data .get ("DnsOptions" ),
885- DnsSearch = data .get ("DnsSearch" ),
886- ExtraHosts = data .get ("ExtraHosts" ),
887- GroupAdd = data .get ("GroupAdd" ),
888- IpcMode = data .get ("IpcMode" ),
889- Cgroup = data .get ("Cgroup" ),
890- Links = data .get ("Links" ),
891- OomScoreAdj = data .get ("OomScoreAdj" ),
892- PidMode = data .get ("PidMode" ),
893- Privileged = data .get ("Privileged" ),
894- PublishAllPorts = data .get ("PublishAllPorts" ),
895- ReadonlyRootfs = data .get ("ReadonlyRootfs" ),
896- SecurityOpt = data .get ("SecurityOpt" ),
897- StorageOpt = data .get ("StorageOpt" ),
898- Tmpfs = data .get ("Tmpfs" ),
899- UTSMode = data .get ("UTSMode" ),
900- UsernsMode = data .get ("UsernsMode" ),
901- ShmSize = data .get ("ShmSize" ),
902- Sysctls = data .get ("Sysctls" ),
903- Runtime = data .get ("Runtime" ),
904- Isolation = data .get ("Isolation" ),
905- MaskedPaths = data .get ("MaskedPaths" ),
906- ReadonlyPaths = data .get ("ReadonlyPaths" ),
907- )
872+ return _ignore_properties (ContainerHostConfig , data )
908873
909874 @classmethod
910875 def _parse_network_settings (cls , data : dict [str , Any ]) -> Optional [ContainerNetworkSettings ]:
911876 """Parse NetworkSettings with nested Networks and Ports."""
912877 if not data :
913878 return None
914-
915- ports : dict [str , Optional [list [ContainerPortBinding ]]] = {}
916- ports_data = data .get ("Ports" )
917- if ports_data is not None :
918- for port , bindings in ports_data .items ():
919- if bindings is None :
920- ports [port ] = None
921- else :
922- ports [port ] = [_ignore_properties (ContainerPortBinding , b ) for b in bindings ]
923-
924- networks = {}
925- networks_data = data .get ("Networks" )
926- if networks_data is not None :
927- for name , network_data in networks_data .items ():
928- networks [name ] = _ignore_properties (ContainerNetworkEndpoint , network_data )
929-
930- secondary_ipv4 = []
931- secondary_ipv4_data = data .get ("SecondaryIPAddresses" )
932- if secondary_ipv4_data is not None :
933- secondary_ipv4 = [_ignore_properties (ContainerAddress , addr ) for addr in secondary_ipv4_data ]
934-
935- secondary_ipv6 = []
936- secondary_ipv6_data = data .get ("SecondaryIPv6Addresses" )
937- if secondary_ipv6_data is not None :
938- secondary_ipv6 = [_ignore_properties (ContainerAddress , addr ) for addr in secondary_ipv6_data ]
939-
940- return ContainerNetworkSettings (
941- Bridge = data .get ("Bridge" ),
942- SandboxID = data .get ("SandboxID" ),
943- HairpinMode = data .get ("HairpinMode" ),
944- LinkLocalIPv6Address = data .get ("LinkLocalIPv6Address" ),
945- LinkLocalIPv6PrefixLen = data .get ("LinkLocalIPv6PrefixLen" ),
946- Ports = ports if ports else None ,
947- SandboxKey = data .get ("SandboxKey" ),
948- SecondaryIPAddresses = secondary_ipv4 if secondary_ipv4 else None ,
949- SecondaryIPv6Addresses = secondary_ipv6 if secondary_ipv6 else None ,
950- EndpointID = data .get ("EndpointID" ),
951- Gateway = data .get ("Gateway" ),
952- GlobalIPv6Address = data .get ("GlobalIPv6Address" ),
953- GlobalIPv6PrefixLen = data .get ("GlobalIPv6PrefixLen" ),
954- IPAddress = data .get ("IPAddress" ),
955- IPPrefixLen = data .get ("IPPrefixLen" ),
956- IPv6Gateway = data .get ("IPv6Gateway" ),
957- MacAddress = data .get ("MacAddress" ),
958- Networks = networks if networks else None ,
959- )
879+ return _ignore_properties (ContainerNetworkSettings , data )
960880
961881 def get_network_settings (self ) -> Optional [ContainerNetworkSettings ]:
962882 """Get network settings for the container."""
0 commit comments