Message ID | 1596118512-424960-10-git-send-email-andrey.shinkevich@virtuozzo.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | iotests: Dump QCOW2 dirty bitmaps metadata | expand |
30.07.2020 17:15, Andrey Shinkevich wrote: > As __dict__ is being extended with class members we do not want to > print, add the to_dict() method to classes that returns a dictionary > with desired fields and their values. Extend it in subclass when > necessary to print the final dictionary in the JSON output which > follows. > > Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> > Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com> > --- > tests/qemu-iotests/qcow2_format.py | 34 ++++++++++++++++++++++++++++++++++ > 1 file changed, 34 insertions(+) > > diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py > index 2000de3..a4114cb 100644 > --- a/tests/qemu-iotests/qcow2_format.py > +++ b/tests/qemu-iotests/qcow2_format.py > @@ -119,6 +119,9 @@ class Qcow2Struct(metaclass=Qcow2StructMeta): > > print('{:<25} {}'.format(f[2], value_str)) > > + def to_dict(self): > + return dict((f[2], self.__dict__[f[2]]) for f in self.fields) > + > > class Qcow2BitmapExt(Qcow2Struct): > > @@ -151,6 +154,11 @@ class Qcow2BitmapExt(Qcow2Struct): > print() > entry.dump() > > + def to_dict(self): > + fields_dict = super().to_dict() > + fields_dict['bitmap_directory'] = self.bitmap_directory > + return fields_dict > + > > class Qcow2BitmapDirEntry(Qcow2Struct): > > @@ -189,6 +197,14 @@ class Qcow2BitmapDirEntry(Qcow2Struct): > super(Qcow2BitmapDirEntry, self).dump() > self.bitmap_table.dump() > > + def to_dict(self): > + fields_dict = super().to_dict() > + fields_dict['bitmap_table'] = self.bitmap_table.entries the fact that we have to access internals of bitmap_table is not nice, but let's refactor it later. > + bmp_name = dict(name=self.name) > + # Put the name ahead of the dict Aha. I don't think that ordering is necessary for json, but why not to order it a bit. > + bme_dict = {**bmp_name, **fields_dict} strange to create bmp_name dict just to unpack it. You may as well do bme_dict = {'name': self.name, **fields_dict} > + return bme_dict bme_dict is extra variable: it's created just to return it, so, how about just return {'name': self.name, **fields_dict} or, maybe return { 'name': self.name, **super().to_dict(), 'bitmap_table': self.bitmap_table.entries } > + > > class Qcow2BitmapTableEntry(Qcow2Struct): > > @@ -214,6 +230,9 @@ class Qcow2BitmapTableEntry(Qcow2Struct): > else: > self.type = 'all-zeroes' > > + def to_dict(self): > + return dict(type=self.type, offset=self.offset, reserved=self.reserved) > + Python has a special syntax for creating dicts :), let's use: return {'type': self.type, 'offset': self.offset, 'reserved': self.reserved} > > class Qcow2BitmapTable: > > @@ -246,6 +265,9 @@ class QcowHeaderExtension(Qcow2Struct): > 0x44415441: 'Data file' > } > > + def to_dict(self): > + return self.mapping.get(self.value, "<unknown>") aha, so, actually, to_dict() returns not dict, but string. So it should better be named to_json() (and return any json-dumpable object, like string or dict) and then, we can add to_json() method to Qcow2BitmapTable as well, to return list. > + > fields = ( > ('u32', Magic, 'magic'), > ('u32', '{}', 'length') > @@ -308,6 +330,18 @@ class QcowHeaderExtension(Qcow2Struct): > else: > self.obj.dump() > > + def to_dict(self): > + fields_dict = super().to_dict() > + ext_name = dict(name=self.Magic(self.magic)) strange that we have to create Magic object here... Ok, let's refactor it later > + # Put the name ahead of the dict > + he_dict = {**ext_name, **fields_dict} > + if self.obj is not None: > + he_dict['data'] = self.obj > + else: > + he_dict['data_str'] = self.data_str > + > + return he_dict again, let's avoid extra dict variables: res = {'name': self.Magic(self.magic), **super().to_dict()} if ... > + > @classmethod > def create(cls, magic, data): > return QcowHeaderExtension(magic, len(data), data) >
On 05.08.2020 19:58, Vladimir Sementsov-Ogievskiy wrote: > 30.07.2020 17:15, Andrey Shinkevich wrote: >> As __dict__ is being extended with class members we do not want to >> print, add the to_dict() method to classes that returns a dictionary >> with desired fields and their values. Extend it in subclass when >> necessary to print the final dictionary in the JSON output which >> follows. >> >> Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> >> Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com> >> --- >> tests/qemu-iotests/qcow2_format.py | 34 >> ++++++++++++++++++++++++++++++++++ >> 1 file changed, 34 insertions(+) >> >> diff --git a/tests/qemu-iotests/qcow2_format.py >> b/tests/qemu-iotests/qcow2_format.py >> index 2000de3..a4114cb 100644 >> --- a/tests/qemu-iotests/qcow2_format.py >> +++ b/tests/qemu-iotests/qcow2_format.py >> @@ -119,6 +119,9 @@ class Qcow2Struct(metaclass=Qcow2StructMeta): >> print('{:<25} {}'.format(f[2], value_str)) >> + def to_dict(self): >> + return dict((f[2], self.__dict__[f[2]]) for f in self.fields) >> + >> class Qcow2BitmapExt(Qcow2Struct): >> @@ -151,6 +154,11 @@ class Qcow2BitmapExt(Qcow2Struct): >> print() >> entry.dump() >> + def to_dict(self): >> + fields_dict = super().to_dict() >> + fields_dict['bitmap_directory'] = self.bitmap_directory >> + return fields_dict >> + >> class Qcow2BitmapDirEntry(Qcow2Struct): >> @@ -189,6 +197,14 @@ class Qcow2BitmapDirEntry(Qcow2Struct): >> super(Qcow2BitmapDirEntry, self).dump() >> self.bitmap_table.dump() >> + def to_dict(self): >> + fields_dict = super().to_dict() >> + fields_dict['bitmap_table'] = self.bitmap_table.entries > > the fact that we have to access internals of bitmap_table is not nice, > but let's refactor it later. > >> + bmp_name = dict(name=self.name) >> + # Put the name ahead of the dict > > Aha. I don't think that ordering is necessary for json, but why not to > order it a bit. > >> + bme_dict = {**bmp_name, **fields_dict} > > > strange to create bmp_name dict just to unpack it. You may as well do > > bme_dict = {'name': self.name, **fields_dict} > >> + return bme_dict > > bme_dict is extra variable: it's created just to return it, so, how > about just > > return {'name': self.name, **fields_dict} > > > or, maybe > > return { > 'name': self.name, > **super().to_dict(), > 'bitmap_table': self.bitmap_table.entries > } > >> + >> class Qcow2BitmapTableEntry(Qcow2Struct): >> @@ -214,6 +230,9 @@ class Qcow2BitmapTableEntry(Qcow2Struct): >> else: >> self.type = 'all-zeroes' >> + def to_dict(self): >> + return dict(type=self.type, offset=self.offset, >> reserved=self.reserved) >> + > > Python has a special syntax for creating dicts :), let's use: > > return {'type': self.type, 'offset': self.offset, 'reserved': > self.reserved} > > >> class Qcow2BitmapTable: >> @@ -246,6 +265,9 @@ class QcowHeaderExtension(Qcow2Struct): >> 0x44415441: 'Data file' >> } >> + def to_dict(self): >> + return self.mapping.get(self.value, "<unknown>") > > aha, so, actually, to_dict() returns not dict, but string. So it > should better be named to_json() (and return any json-dumpable object, > like string or dict) > > and then, we can add to_json() method to Qcow2BitmapTable as well, to > return list. So, should I refactor it now? Andrey > > >> + >> fields = ( >> ('u32', Magic, 'magic'), >> ('u32', '{}', 'length') >> @@ -308,6 +330,18 @@ class QcowHeaderExtension(Qcow2Struct): >> else: >> self.obj.dump() >> + def to_dict(self): >> + fields_dict = super().to_dict() >> + ext_name = dict(name=self.Magic(self.magic)) > > strange that we have to create Magic object here... Ok, let's refactor > it later > >> + # Put the name ahead of the dict >> + he_dict = {**ext_name, **fields_dict} >> + if self.obj is not None: >> + he_dict['data'] = self.obj >> + else: >> + he_dict['data_str'] = self.data_str >> + >> + return he_dict > > again, let's avoid extra dict variables: > > res = {'name': self.Magic(self.magic), **super().to_dict()} > if ... > > >> + >> @classmethod >> def create(cls, magic, data): >> return QcowHeaderExtension(magic, len(data), data) >> > >
06.08.2020 12:08, Andrey Shinkevich wrote: > On 05.08.2020 19:58, Vladimir Sementsov-Ogievskiy wrote: >> 30.07.2020 17:15, Andrey Shinkevich wrote: >>> As __dict__ is being extended with class members we do not want to >>> print, add the to_dict() method to classes that returns a dictionary >>> with desired fields and their values. Extend it in subclass when >>> necessary to print the final dictionary in the JSON output which >>> follows. >>> >>> Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> >>> Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com> >>> --- >>> tests/qemu-iotests/qcow2_format.py | 34 ++++++++++++++++++++++++++++++++++ >>> 1 file changed, 34 insertions(+) >>> >>> diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py >>> index 2000de3..a4114cb 100644 >>> --- a/tests/qemu-iotests/qcow2_format.py >>> +++ b/tests/qemu-iotests/qcow2_format.py >>> @@ -119,6 +119,9 @@ class Qcow2Struct(metaclass=Qcow2StructMeta): >>> print('{:<25} {}'.format(f[2], value_str)) >>> + def to_dict(self): >>> + return dict((f[2], self.__dict__[f[2]]) for f in self.fields) >>> + >>> class Qcow2BitmapExt(Qcow2Struct): >>> @@ -151,6 +154,11 @@ class Qcow2BitmapExt(Qcow2Struct): >>> print() >>> entry.dump() >>> + def to_dict(self): >>> + fields_dict = super().to_dict() >>> + fields_dict['bitmap_directory'] = self.bitmap_directory >>> + return fields_dict >>> + >>> class Qcow2BitmapDirEntry(Qcow2Struct): >>> @@ -189,6 +197,14 @@ class Qcow2BitmapDirEntry(Qcow2Struct): >>> super(Qcow2BitmapDirEntry, self).dump() >>> self.bitmap_table.dump() >>> + def to_dict(self): >>> + fields_dict = super().to_dict() >>> + fields_dict['bitmap_table'] = self.bitmap_table.entries >> >> the fact that we have to access internals of bitmap_table is not nice, but let's refactor it later. >> >>> + bmp_name = dict(name=self.name) >>> + # Put the name ahead of the dict >> >> Aha. I don't think that ordering is necessary for json, but why not to order it a bit. >> >>> + bme_dict = {**bmp_name, **fields_dict} >> >> >> strange to create bmp_name dict just to unpack it. You may as well do >> >> bme_dict = {'name': self.name, **fields_dict} >> >>> + return bme_dict >> >> bme_dict is extra variable: it's created just to return it, so, how about just >> >> return {'name': self.name, **fields_dict} >> >> >> or, maybe >> >> return { >> 'name': self.name, >> **super().to_dict(), >> 'bitmap_table': self.bitmap_table.entries >> } >> >>> + >>> class Qcow2BitmapTableEntry(Qcow2Struct): >>> @@ -214,6 +230,9 @@ class Qcow2BitmapTableEntry(Qcow2Struct): >>> else: >>> self.type = 'all-zeroes' >>> + def to_dict(self): >>> + return dict(type=self.type, offset=self.offset, reserved=self.reserved) >>> + >> >> Python has a special syntax for creating dicts :), let's use: >> >> return {'type': self.type, 'offset': self.offset, 'reserved': self.reserved} >> >> >>> class Qcow2BitmapTable: >>> @@ -246,6 +265,9 @@ class QcowHeaderExtension(Qcow2Struct): >>> 0x44415441: 'Data file' >>> } >>> + def to_dict(self): >>> + return self.mapping.get(self.value, "<unknown>") >> >> aha, so, actually, to_dict() returns not dict, but string. So it should better be named to_json() (and return any json-dumpable object, like string or dict) >> >> and then, we can add to_json() method to Qcow2BitmapTable as well, to return list. > > > So, should I refactor it now? > Up to you. Better yes if not difficult > > >> >> >>> + >>> fields = ( >>> ('u32', Magic, 'magic'), >>> ('u32', '{}', 'length') >>> @@ -308,6 +330,18 @@ class QcowHeaderExtension(Qcow2Struct): >>> else: >>> self.obj.dump() >>> + def to_dict(self): >>> + fields_dict = super().to_dict() >>> + ext_name = dict(name=self.Magic(self.magic)) >> >> strange that we have to create Magic object here... Ok, let's refactor it later >> >>> + # Put the name ahead of the dict >>> + he_dict = {**ext_name, **fields_dict} >>> + if self.obj is not None: >>> + he_dict['data'] = self.obj >>> + else: >>> + he_dict['data_str'] = self.data_str >>> + >>> + return he_dict >> >> again, let's avoid extra dict variables: >> >> res = {'name': self.Magic(self.magic), **super().to_dict()} >> if ... >> >> >>> + >>> @classmethod >>> def create(cls, magic, data): >>> return QcowHeaderExtension(magic, len(data), data) >>> >> >>
diff --git a/tests/qemu-iotests/qcow2_format.py b/tests/qemu-iotests/qcow2_format.py index 2000de3..a4114cb 100644 --- a/tests/qemu-iotests/qcow2_format.py +++ b/tests/qemu-iotests/qcow2_format.py @@ -119,6 +119,9 @@ class Qcow2Struct(metaclass=Qcow2StructMeta): print('{:<25} {}'.format(f[2], value_str)) + def to_dict(self): + return dict((f[2], self.__dict__[f[2]]) for f in self.fields) + class Qcow2BitmapExt(Qcow2Struct): @@ -151,6 +154,11 @@ class Qcow2BitmapExt(Qcow2Struct): print() entry.dump() + def to_dict(self): + fields_dict = super().to_dict() + fields_dict['bitmap_directory'] = self.bitmap_directory + return fields_dict + class Qcow2BitmapDirEntry(Qcow2Struct): @@ -189,6 +197,14 @@ class Qcow2BitmapDirEntry(Qcow2Struct): super(Qcow2BitmapDirEntry, self).dump() self.bitmap_table.dump() + def to_dict(self): + fields_dict = super().to_dict() + fields_dict['bitmap_table'] = self.bitmap_table.entries + bmp_name = dict(name=self.name) + # Put the name ahead of the dict + bme_dict = {**bmp_name, **fields_dict} + return bme_dict + class Qcow2BitmapTableEntry(Qcow2Struct): @@ -214,6 +230,9 @@ class Qcow2BitmapTableEntry(Qcow2Struct): else: self.type = 'all-zeroes' + def to_dict(self): + return dict(type=self.type, offset=self.offset, reserved=self.reserved) + class Qcow2BitmapTable: @@ -246,6 +265,9 @@ class QcowHeaderExtension(Qcow2Struct): 0x44415441: 'Data file' } + def to_dict(self): + return self.mapping.get(self.value, "<unknown>") + fields = ( ('u32', Magic, 'magic'), ('u32', '{}', 'length') @@ -308,6 +330,18 @@ class QcowHeaderExtension(Qcow2Struct): else: self.obj.dump() + def to_dict(self): + fields_dict = super().to_dict() + ext_name = dict(name=self.Magic(self.magic)) + # Put the name ahead of the dict + he_dict = {**ext_name, **fields_dict} + if self.obj is not None: + he_dict['data'] = self.obj + else: + he_dict['data_str'] = self.data_str + + return he_dict + @classmethod def create(cls, magic, data): return QcowHeaderExtension(magic, len(data), data)
As __dict__ is being extended with class members we do not want to print, add the to_dict() method to classes that returns a dictionary with desired fields and their values. Extend it in subclass when necessary to print the final dictionary in the JSON output which follows. Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com> --- tests/qemu-iotests/qcow2_format.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)