'how to ignore extra kwargs in python-attrs class

For example:

@attrs
class Foo:
  a = attrib()

f = Foo(a=1, b=2)

Code above will throw an error because class Foo doesn't have b attr. But I want to discard passed b value as if I just called f = Foo(a=1). In my use case I have dynamic dict (which I want to transform into attr-class) and I simply do not need some of the keys.



Solution 1:[1]

I think I figured out a more elegant solution which allows you to take advantage of the features of attrs while also tweaking the __init__ logic. See attrs documentation for more info.

@attr.s(auto_attribs=True, auto_detect=True)
class Foo():
    a: int
    optional: int = 3

    def __init__(self,**kwargs):
      filtered = {
        attribute.name: kwargs[attribute.name]
        for attribute in self.__attrs_attrs__
        if attribute.name in kwargs
      }
      self.__attrs_init__(**filtered)

The code above allows you to specify extraneous keyword args. It also allows for optional args.

>>> Foo(a = 1, b = 2)
Foo(a=1, optional=3)

attrs detects the explicit init method (due to auto_detect=True) and still creates the init function, but calls it __attrs_init__. This allows you do define your own init function to do preprocessing and then call __attrs_init__ when you are done.

>>> import inspect
>>> print(inspect.getsource(Foo.__attrs_init__))
def __attrs_init__(self, a, optional=attr_dict['optional'].default):
    self.a = a
    self.optional = optional

Solution 2:[2]

class FromDictMixin:
    @classmethod
    def from_dict(cls, data: dict):
        return cls(**{
            a.name: data[a.name]
            for a in cls.__attrs_attrs__
        })

@attrs
class Foo(FromDictMixin):
    a = attrib()

It works, but it looks kinda ugly. I was hopping that attrs lib had out of the box solution.

Solution 3:[3]

This seems to be more of a question of serialization/deserialization/validation and attrs is quite strict on its argument for multiple reasons. One of them is typing (as in types, not pressing keys :)) and the other is robustness/debugabiity. Ignoring arguments that you might have just misspelt can lead to very frustrating moments. It's better to move this kind of stuff into a separate layer.

You can find some possible tools for that in https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs.

Solution 4:[4]

I had to do something similar but I didn't want to write a custom __init__ method for every class. So I created a decorator where it would attach an __init__ method to the class before instantiation then wrap in attrs.define decorator.

This is just an example but does what you want.

import attrs


def define(cls):
    def __init__(cls, **kwargs):
        filtered = {}
        for attr in cls.__attrs_attrs__:
            if attr.name in kwargs:
                filtered[attr.name] = kwargs[attr.name]
        cls.__attrs_init__(**filtered)

    def wrapper(*args, **kwargs):
        nonlocal cls
        cls.__init__ = __init__
        cls = attrs.define(cls)
        return cls(*args, **kwargs)

    return wrapper


@define
class Booking:
    id: int
    id_hash: str


booking = {"id": 1, "id_hash": "a3H33lk", "foo": "bar"}
b = Booking(**booking)
print(b)
# Booking(id=1, id_hash='a3H33lk')

Solution 5:[5]

Does this fix your issues?

from multiprocessing import Pool
import os

def change_video_file_type_for_multy_proccecing(file_path):
   os.system('ffmpeg -i ' + file_path+ ' -vcodec h264 -acodec mp2 -q:v 0 ' + file_path.replace(".MOV",".mp4"))

input_for_after_trim = "/home/oem/Documents/2021/MOV/after_trim"
output_for_after_trim = "/home/oem/Documents/2021/mp4/after_trim"
file_path_list = []
for filename in os.listdir(input_for_after_trim):
   file_path_list.append(input_for_after_trim+"/"+filename)

num_processes = os.cpu_count() #just an example, set to what you want
with Pool(num_processes) as p:
   results = list(p.map(change_video_file_type_for_multy_proccecing,file_path_list))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Porkins
Solution 2 aiven
Solution 3 hynek
Solution 4 Jeff
Solution 5 Phoenix