Monday, November 7, 2022

Python Metaclasses

Copy it to a fixed width font terminal for a good reading. 

This is what I gathered and guessed about Python metaclasses from the following pages: 

https://mail.python.org/pipermail/python-3000/2006-December/005030.html

https://www.geeksforgeeks.org/python-metaclasses/

https://realpython.com/python-metaclasses/

https://www.geeksforgeeks.org/metaprogramming-metaclasses-python/

Python is a work in progress and so is my understanding of this programming language. 


dynamically create a new class: 

'name' = type('name', 'bases', 'dict') 

  differs from class 'name''bases' 

    by the fact that the name, bases and attributes of the newly created class are decided at runtime 

  'name' - the name of the new class, memorized in 'name'. __name__ 

  'bases' - a tuple of the base classes from which the class inherits, memorized in 'name'.__bases__ 

  'dict' - a namespace dictionary containing definitions for the class body, memorized in 'name'.__dict__


metaclasses configure classes when they are created 

    this is different from inheritance 

  all classes inherit the class 'object' or its subclasses 

  all classes are configured by the metaclass 'type' or a subclass of it 

    (maybe it has to be a direct subclass) 

  'myclass'.__bases__, 'myclass'.__base__ - show directly inherited classes 

  'myclass'.__class__, type('myclass') - show the metaclass that configured 'myclass' 

   >>> type.__bases__ 

   (<class 'object'>,)

   >>> type(type) 

   <class 'type'>

   >>> int.__bases__ 

   (<class 'object'>,)

   >>> type(int) 

   <class 'type'>

   >>> type(7) 

   <class 'int'>


objects have a __call__() method  

  which calls the __new__() and __init__() methods

  __new__() creates the new object and returns it

    'cls' in __new__() is the new object

  __init__() initializes the newly created object passed as a parameter

    'self' in __init__() is the new object

  these methods can be overridden to configure the newly created object

  help(type.__call__), help(object.__call__)

  help(type) has a __call__ method, but help(object) does not


metaclasses are a “solution in search of a problem” 


examples of metaclass usage 

$ cat meta.py 


# MyMeta  is an instance of type   and a subclass of type 

# MyClass is an instance of MyMeta and a subclass of object 


def prints(): 

  print('   type(MyMeta) =', type(MyMeta), '\n   type(MyClass) =', type(MyClass), '\n') 


class MyClass: 

  pass 


# dynamic creation (definition) of MyClass, parameters can be decided at runtime 

MyClass = type('MyClass', (object,), {}) 


class MyMeta(type): 

  def __new__(cls, cls_name, bases, attrib): 

    print('>> MyMeta.__new__()') 

    return super(MyMeta, cls).__new__(cls, cls_name, bases, attrib) 

#          super() arguments are not required 


print('\nMyMeta.__bases__ =', MyMeta.__bases__, '\nMyMeta.__class__ =', MyMeta.__class__, '\n') 


class MyClass(metaclass = MyMeta): 

  pass 


prints() 


MyClass = MyMeta('MyClass', (object, ), {}) 


prints() 


# MyClass = type('MyClass', (object, metaclass = MyMeta,), {}) 

#                             invalid syntax   ^ 

#   so type() cannot create a class of a MyMeta type 

# prints() 


# MyClass = MyMeta() 

#   new() missing 3 required positional arguments: 'cls_name', 'bases', and 'attrib' 

# prints() 


def new(cls, cls_name, bases, attrib): 

  print('>> new()') 

  return super(MyMeta, cls).__new__(cls, cls_name, bases, attrib) 

#        super() arguments are required 


MyMeta = type('MyMeta', (type,), {'__new__' : new}) 


class MyClass(metaclass = MyMeta): 

  pass 


prints() 


$ python meta.py 


MyMeta.__bases__ = (<class 'type'>,) 

MyMeta.__class__ = <class 'type'> 


>> MyMeta.__new__()

   type(MyMeta) = <class 'type'> 

   type(MyClass) = <class '__main__.MyMeta'> 


>> MyMeta.__new__()

   type(MyMeta) = <class 'type'> 

   type(MyClass) = <class '__main__.MyMeta'> 


>> new()

   type(MyMeta) = <class 'type'> 

   type(MyClass) = <class '__main__.MyMeta'> 


$ cat meta.py 

class Meta(type):

  def __new__(cls, name, bases, dict):

    x = super().__new__(cls, name, bases, dict)

    x.attr = 100

    return x

class Foo(metaclass=Meta):

  pass

print('Foo.attr =', Foo.attr)

$ python meta.py 

Foo.attr = 100


$ cat meta.py 

class Meta(type):

  def __init__(cls, name, bases, dict):

    cls.attr = 100

class X(metaclass=Meta):

  pass

print('X.attr =', X.attr)

$ python meta.py 

X.attr = 100


Friday, December 8, 2017

zoom pdf for printing

This may help to install pdfedit on Ubuntu 14.04 Trusty https://askubuntu.com/questions/538966/how-can-i-install-pdfedit-on-ubuntu-14-04 and this on Ubuntu 16.04 Xenial https://gist.github.com/bmaupin/a23161b50f27179e6e5b064d6066b034.

Start pdfedit.

If the pdf file is uneditable then Tools > Delinearize it.

Use Page > Set page transformation matrix to find the transformation you want. You need to check Page transformation matrix description > Select which transformations to use. This only changes one page.

The programming language used is the qt script language, ECMAScript, almost identical to JavaScript. The API functions are listed in Help > Help.

Save this https://sourceforge.net/p/pdfedit/mailman/pdfedit-support/thread/20080707173451.GG4157%40dhcp35.suse.cz/ inspired script in ./zoom.qs:
f = loadPdf("myfile.pdf");
pg = f.getFirstPage();
pg.setTransformMatrix([1.4,0,0,1.4,-130,-180]);
while (f.hasNextPage(pg)) {
pg = f.getNextPage(pg);
pg.setTransformMatrix([1.4,0,0,1.4,-130,-180]); }
f.save();
f.unloadPdf();


Modify the arguments of setTransformMatrix into your desired ones found using Page > Set page transformation matrix. Parameters 1 and 4 should not be 0, that would make the text invisible.

Copy your pdf file to be processed in ./myfile.pdf.

Issue:
$ pdfedit -s zoom.qs

You can print with:
$ lp -o media-size=a4,fit-to-page -P 1 myfile.pdf

It would be nice to calculate the transformation matrix using the printer acceptable minimal margins, but I don't know how to get the current margins of the document.

Tuesday, October 20, 2015

archlinux pacman - an introduction

Packages in arch repositories are constantly upgraded. When a package is upgraded, its old version is removed from the repository. There are no major arch releases. Each package is upgraded as new versions become available from upstream sources. The repository is always coherent. (The packages in the repository always have compatible versions.) This type of repository is called a rolling repository. Before packages are upgraded in the core, extra and community repositories, they are tested in the testing repository, to ensure that the distribution is stable.

pacman saves to disk a list of packages available in the repository. This list is not automatically updated (refreshed). (The list is a.k.a. repository databases and the update of the list is a.k.a. synchronizing those databases.) The list can be refreshed using pacman -Sy. pacman -Syy refreshes the list even if it appears to be up to date. I don't know the effect of pacman -Syy when the pacman list is newer than that of the mirror, for example as a result of falling back to a different not yet updated mirror.

When the list is outdated it is possible that packages to be installed with pacman -S package are not available.

When pacman installs one package with pacman -S package it takes care that all its correct version dependencies are installed but it does not verify that dependencies of other packages are not broken by such updates. If the list has been updated but packages not, then this command could make the system unusable. That is why the list should only be updated together with all packages in the system with pacman -Syu and you should never run pacman -Sy or pacman -Sy package.