diff options
Diffstat (limited to 'src/pikepdf/objects.py')
-rw-r--r-- | src/pikepdf/objects.py | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/src/pikepdf/objects.py b/src/pikepdf/objects.py index a888b97..2e42eb9 100644 --- a/src/pikepdf/objects.py +++ b/src/pikepdf/objects.py @@ -8,24 +8,33 @@ The purpose of these is to provide nice-looking classes to allow explicit construction of PDF objects and more pythonic idioms and facilitate discovery -by documentation generators. +by documentation generators and linters. It's also a place to narrow the scope of input types to those more easily converted to C++. -In reality all of these return objects of class pikepdf.Object or rather -QPDFObjectHandle which is a generic type. - +There is some deliberate "smoke and mirrors" here: all of the objects are truly +instances of ``pikepdf.Object``, which is a variant container object. The +``__new__`` constructs a ``pikepdf.Object`` in each case, and the rest of the +class definition is present as an aide for code introspection. """ from . import _qpdf -from ._qpdf import Object, ObjectType -# pylint: disable=unused-import -from ._qpdf import Operator +# pylint: disable=unused-import, abstract-method +from ._qpdf import Object, ObjectType, Operator + +# By default pikepdf.Object will identify itself as pikepdf._qpdf.Object +# Here we change the module to discourage people from using that internal name +# Instead it will become pikepdf.objects.Object +Object.__module__ = __name__ +ObjectType.__module__ = __name__ +Operator.__module__ = __name__ -class _ObjectMeta(type): + +# type(Object) is the metaclass that pybind11 defines; we wish to extend that +class _ObjectMeta(type(Object)): """Supports instance checking""" def __instancecheck__(cls, instance): @@ -38,9 +47,13 @@ class _NameObjectMeta(_ObjectMeta): """Supports usage pikepdf.Name.Whatever -> Name('/Whatever')""" def __getattr__(self, attr): + if attr.startswith('_'): + return _ObjectMeta.__getattr__(attr) return Name('/' + attr) - def __setattr__(self, name, value): + def __setattr__(self, attr, value): + if attr.startswith('_'): + return _ObjectMeta.__setattr__(attr, value) raise TypeError("Attributes may not be set on pikepdf.Name") def __getitem__(self, item): @@ -56,7 +69,7 @@ class _NameObjectMeta(_ObjectMeta): ) -class Name(metaclass=_NameObjectMeta): +class Name(Object, metaclass=_NameObjectMeta): """Constructs a PDF Name object Names can be constructed with two notations: @@ -69,6 +82,7 @@ class Name(metaclass=_NameObjectMeta): that are normally expected to be in a PDF. The latter is preferred for dynamic names and attributes. """ + object_type = ObjectType.name def __new__(cls, name): @@ -79,8 +93,9 @@ class Name(metaclass=_NameObjectMeta): return _qpdf._new_name(name) -class String(metaclass=_ObjectMeta): +class String(Object, metaclass=_ObjectMeta): """Constructs a PDF String object""" + object_type = ObjectType.string def __new__(cls, s): @@ -97,8 +112,9 @@ class String(metaclass=_ObjectMeta): return _qpdf._new_string_utf8(s) -class Array(metaclass=_ObjectMeta): +class Array(Object, metaclass=_ObjectMeta): """Constructs a PDF Array object""" + object_type = ObjectType.array def __new__(cls, a=None): @@ -118,8 +134,9 @@ class Array(metaclass=_ObjectMeta): return _qpdf._new_array(a) -class Dictionary(metaclass=_ObjectMeta): +class Dictionary(Object, metaclass=_ObjectMeta): """Constructs a PDF Dictionary object""" + object_type = ObjectType.dictionary def __new__(cls, d=None, **kwargs): @@ -147,15 +164,15 @@ class Dictionary(metaclass=_ObjectMeta): if kwargs: # Add leading slash # Allows Dictionary(MediaBox=(0,0,1,1), Type=Name('/Page')... - return _qpdf._new_dictionary( - {('/' + k) : v for k, v in kwargs.items()}) + return _qpdf._new_dictionary({('/' + k): v for k, v in kwargs.items()}) if not d: d = {} return _qpdf._new_dictionary(d) -class Stream(metaclass=_ObjectMeta): +class Stream(Object, metaclass=_ObjectMeta): """Constructs a PDF Stream object""" + object_type = ObjectType.stream def __new__(cls, owner, obj): |