Updated extractar.py using attrs
The ArchiveInfo class now uses the attrs library and slots over instance dictionaries. Class now explicitly inherits from class object for custom setattr dunder method in AchiveInfo. This override allows for immutability of class attributes, and flexible mutability when appropriate.
This commit is contained in:
parent
50443715fc
commit
db6dad845f
51
extractar.py
51
extractar.py
|
|
@ -9,7 +9,8 @@
|
|||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
# this list of conditions and the following disclaimer in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
|
|
@ -30,6 +31,8 @@ import os
|
|||
import struct
|
||||
import textwrap
|
||||
import pathlib
|
||||
from typing import Any
|
||||
import attr
|
||||
|
||||
__version__ = '1.0'
|
||||
|
||||
|
|
@ -56,8 +59,8 @@ class ArchiveBufferReadError(IndexError):
|
|||
Debian binary package entry information. Exception is of type IndexError.
|
||||
"""
|
||||
|
||||
|
||||
class ArchiveInfo:
|
||||
@attr.s(slots=True)
|
||||
class ArchiveInfo(object):
|
||||
"""
|
||||
Information on a file in an archive.
|
||||
|
||||
|
|
@ -76,19 +79,13 @@ class ArchiveInfo:
|
|||
the same name are present; if you change the `name` attribute, the initial
|
||||
file will be extracted with the new name (and new metadata).
|
||||
"""
|
||||
def __init__(self, name: bytes, size: int, mtime: int, perms: int, uid: int, gid: int):
|
||||
self._name = name
|
||||
self.size = size
|
||||
self.mtime = mtime
|
||||
self.perms = perms
|
||||
self.uid = uid
|
||||
self.gid = gid
|
||||
self.offset: int = 0
|
||||
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
name: bytes = attr.ib(converter=lambda s: _utf8(s).rstrip(b' '), on_setattr=attr.setters.NO_OP)
|
||||
size: int = attr.ib(converter=int)
|
||||
mtime: int = attr.ib(converter=int)
|
||||
perms: int = attr.ib(converter=lambda x: int(x, 8))
|
||||
uid: int = attr.ib(converter=int)
|
||||
gid: int = attr.ib(converter=int)
|
||||
offset: int = attr.ib(converter=int, default=0)
|
||||
|
||||
|
||||
@classmethod
|
||||
|
|
@ -111,19 +108,30 @@ class ArchiveInfo:
|
|||
if magic != b'\x60\n':
|
||||
raise ValueError("Invalid file signature")
|
||||
|
||||
return cls(_utf8(name).rstrip(b' '), int(size, 10), int(mtime, 10), int(perms, 8), int(uid, 10), int(gid, 10))
|
||||
return cls(name=name, size=size, mtime=mtime, perms=perms, uid=uid, gid=gid)
|
||||
|
||||
|
||||
def __setattr__(self, __name: str, __value: Any) -> None:
|
||||
"""
|
||||
Custom setattr dunder method to create strict immutability over certain attributes of a class. Any attributes
|
||||
which may be mutable should be handled appropriately.
|
||||
"""
|
||||
# |------ immutable ------| |---- mutable ----|
|
||||
if not hasattr(self, __name) or __name == "offset":
|
||||
object.__setattr__(self, __name, __value)
|
||||
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return textwrap.dedent('''\
|
||||
ArchiveInfo: ({0})
|
||||
{7}: ({0})
|
||||
_name: {0}
|
||||
size: {1}
|
||||
mtime: {2}
|
||||
perms: {3}
|
||||
uid: {4}
|
||||
gid: {5}
|
||||
offset: {6}\n'''.format(self._name, self.size, self.mtime, self.perms, self.uid, self.gid, self.offset))
|
||||
offset: {6}\n'''.format(self.name, self.size, self.mtime, self.perms, self.uid, self.gid, self.offset,
|
||||
self.__class__))
|
||||
|
||||
|
||||
class Archive:
|
||||
|
|
@ -265,9 +273,9 @@ class Archive:
|
|||
|
||||
# write out the specific content of an archive member
|
||||
pos = member.offset + 60
|
||||
# @TODO: put in try cus IO be IO lmao
|
||||
with open(path, 'wb') as fp:
|
||||
data = self.__ar_contents[pos:pos+member.size]
|
||||
fp.write(data)
|
||||
fp.write(self.__ar_contents[pos:pos+member.size])
|
||||
|
||||
|
||||
def extractall(self, path: str | bytes = ''):
|
||||
|
|
@ -287,4 +295,3 @@ class Archive:
|
|||
# iterate over all members in the mapping
|
||||
for name in self._mapping.keys():
|
||||
self.extract(name, os.path.join(_utf8(path), name))
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user