Thursday, February 27, 2025

How can I use the Gradle documentation to find out how to add a plugin?

 I'm only trying to compile simple programs in Android Studio. However, Gradle proves to be a challenge, not least because of it's elliptic documentation.

1. How can I use the official Gradle documentation to find out which function is called in a Gradle script?
For example, the Android Studio's Empty Activity default configuration features a project_name/app/build.gradle.kts file that begins with this function call:

plugins {
    alias(libs.plugins.androidApplication)
    alias(libs.plugins.jetbrainsKotlinAndroid)
}

In order to find out which plugins function is called, I use the following information:

every Groovy build script is backed by an implicit instance of Project. If you see an unqualified element and you don’t know where it’s defined, always check the Project API documentation to see if that’s where it’s coming from.

On this page there is a plugins function. Now, to identify the alias functions called in the lambda argument, I searched alias and I found four functions: open fun alias(notation: Provider<PluginDependency>): PluginDependencySpec and alias(notation: ProviderConvertible<PluginDependency>): PluginDependencySpec, open override fun alias(notation: Provider<PluginDependency>): PluginDependencySpec and open override fun alias(notation: ProviderConvertible<PluginDependency>): PluginDependencySpec. They all return a PluginDependencySpec object, and therefore they are incompatible with the plugins function, which accepts Unit returning lambdas. Which alias is called depends on the delegate object and the type of the argument. I don't know how to find out any of them. I could not find the source code to find out the delegate object, and I could not find the type of the argument by searching the site.

However, if I hover the mouse over plugins in the script I get an infotip saying that the function is defined in org.gradle.kotlin.dsl.KotlinBuildScript as plugins(PluginDependenciesSpecScope.() -> Unit): Unit. The KotlinBuildScript abstract class declares two plugins functions, one of them indeed receives a PluginDependenciesSpecScope.() -> Unit function, as specified in the hint in the script next to plugins. But when I hover over the second alias, the infotip says that it returns a PluginDependencySpec object, not Unit. Indeed, there is an alias function in PluginDependenciesSpecScope that returns a PluginDependencySpec object, like the infotip says. Kotlin does not accept an incompatible return type. And how was I supposed to know, from the documentation, that the alias function is called with a PluginDependencySpec delegate object?

So the first strategy led me to this plugin and the second to this plugin. Also, both strategies feature an incompatible object type returned by the second alias. How am I supposed to use the official Gradle documentation to find out which functions are called in these four lines of code?

2. Both found plugins functions are deprecated in Gradle 9. Using them will trigger an error:
- the first one

Deprecated (with error)
The plugins {} block must not be used here. If you need to apply a plugin imperatively, please use apply<PluginType>() or apply(plugin = "id") instead.
- the second one has its whole class deprecated:
Deprecated
Will be removed in Gradle 9.0

They are supposed to be replaced by apply:
If you need to apply a plugin imperatively, please use apply() or apply(plugin = "id") instead.
project(":core") {
apply(plugin = "java")
}
The following statements make me believe that the plugins call can be replaced with an apply call with no repercussions on the rest of the script:
The plugins {} block serves a similar purpose to the apply method that can be used to apply a plugin directly to a Project object or similar. A key difference is that plugins applied via the plugins {} block are conceptually applied to the script, and by extension the script target. At this time there is no observable practical difference between the two approaches with regard to the end result.
link 

If you need to apply a plugin imperatively, please use apply() or apply(plugin = "id") instead.
project(":core") {
    apply(plugin = "java")
}

link

However, I utterly failed to find a solution. Many apply syntax constructs are accepted, but the plugin is not added. Please show me how it's done and also show me how you found out the solution from the official Gradle documentation site. Also, how do I find out what am I supposed to put in place of ":core" as an argument to project, if required.

Sunday, December 1, 2024

Java Generic Wildcards

this text is best read in a fixed width terminal 


C++ compiles code for each required parameterized type
Java compiles only one instance of the parameterized type, using Object as the type

because generic types in java erase information on type
  and still the type must be verified by the compiler
  there are cases when the code should compile but it doesn't
  the solution was to relax type checks at compile time


a the '?' wildcard can only appear as the type of a variable or formal parameter declaration
  it imposes constraints on the right hand side of the assignment or on the actual parameter

a variable of <? extends MyClass> type can only refer objects of types that inherit MyClass
    this sets an upper bound
  you can't write to it because
    the compiler can't ensure that what you write is a derivate of its current content
    and therefore it cannot enforce homogeneity (?!)
  you can read <? super MyClass>'s from it
  this variable is a producer

a variable of <? super MyClass> type can only refer objects of types that are inherited by MyClass
    this sets a lower bound
  you can write <? extends MyClass>'s to it
  you can only read in Object's from it because the compiler only knows that it is a derivate of Object
  this variable is a consumer

variables of <?> type can refer objects of any type
  you can not write to it because
    the compiler can't ensure that what you write is a derivate of its current content
    and therefore it cannot enforce homogeneity (?!)
  you can only read in Object's from it because the compiler only knows that it is a derivate of Object

these constraints are verified at compile time

you can combine generics and wildcards: https://www.baeldung.com/java-generics-type-parameter-vs-wildcard

class Wild {
  public static void main(String args[]) {

    /*
    all errors are compile time

    as long as the type of right hand side in the variable declaration
        is compatible with the variable type,
      its type does not influence future compatibilities of the variable
      because its type in the assigned variable is not known to the compiler at the compile time

    of course, anything can be done with explicit type casts
    */


    MyGen<? extends MyClass> ge = new MyGen<MyClass>(new MyClass(1, 2));
      // ge = MyGen, extends
    // ge.e cannot be written but it can be read
    //   ge.e cannot be written because it may hold any class equal to or below MyClass
    //   and they need to ensure ge.e's homogeneity (?!)
    // ge.e is a producer
    // ge.e = new MyBase(3);
      // ByBase cannot be converted to CAP#1
      //   CAP#1 extends MyClass from capture of ? extends MyClass
    // ge.e = new MyClass(4, 5);
      // MyClass cannot be converted to CAP#1
      //   CAP#1 extends MyClass from capture of ? extends MyClass
    // ge.e = new MyDeriv(6, 7, 8);
      // MyDeriv cannot be converted to CAP#1
      //   CAP#1 extends MyClass from capture of ? extends MyClass
    MyBase geb = ge.e;
    MyClass gec = ge.e;
    // MyDeriv ged = ge.e;
      // incompatible types, ge.e can have any type equal or below MyClass
    System.out.println("ge.e = " + ge.e + "\t\tge.e.i = " + ge.e.i + "\tge.e.j = " + ge.e.j);


    MyGen<? super MyClass> gs = new MyGen<MyClass>(new MyClass(1, 2));
      // gs = MyGen, super
    // gs.e can be written but it can be read only into an Object
    //   gs.e can be read only into an Object because it may hold any class equal or above MyClass
    // gs.e is a consumer
    // gs.e = new MyBase(3);
      // incompatible types, gs.e can have any type equal to or above MyClass
    gs.e = new MyClass(4, 5);
    gs.e = new MyDeriv(6, 7, 8);
    // MyBase gsb = gs.e;
      // CAP#1 cannot be converted to MyBase
      //   CAP#1 extends Object super: MyClass from capture of ? super MyClass
    // MyClass gsc = gs.e;
      // CAP#1 cannot be converted to MyClass
      //   CAP#1 extends Object super: MyClass from capture of ? super MyClass
    // MyDeriv gsd = gs.e;
      // CAP#1 cannot be converted to MyDeriv
      //   CAP#1 extends Object super: MyClass from capture of ? super MyClass
    Object gso = gs.e;
    // the type of gs.e is known at run time
    System.out.println("gs.e class is: " + gs.e.getClass().getName());
      // gs.e class is: MyDeriv
    // but not at compile time, when gs.e is only known to be of type Object
    // System.out.println("gs.e = " + gs.e + "\t\tgs.e.i = " + gs.e.i + "\tgs.e.j = " + gs.e.j +
    //                      "\tgs.e.k = " + gs.e.k);
      // cannot find symbols gs.e.i, gs.e.j and gs.e.k


    MyGen<?> g = new MyGen<MyClass>(new MyClass(1, 2));
    // g = MyGen
    // we know nothing about the type of g
    //   so the only allowed operation is to read it into an Object
    // g.e = new MyBase(3);
      // MyBase cannot be converted to CAP#1
      //   CAP#1 extends Object from capture of ?
    // g.e = new MyClass(4, 5);
      // MyClass cannot be converted to CAP#1
      //   CAP#1 extends Object from capture of ?
    // g.e = new MyDeriv(6, 7, 8);
      // MyDeriv cannot be converted to CAP#1
      //   CAP#1 extends Object from capture of ?
    // MyBase gb = g.e;
      // CAP#1 cannot be converted to MyBase
      //   CAP#1 extends Object from capture of ?
    // MyClass gc = g.e;
      // CAP#1 cannot be converted to MyClass
      //   CAP#1 extends Object from capture of ?
    // MyDeriv gd = g.e;
      // CAP#1 cannot be converted to MyDeriv
      //   CAP#1 extends Object from capture of ?
    Object go = g.e;
    // System.out.println("g.e = " + g.e + "\t\tg.e.i = " + g.e.i + "\tg.e.j = " + g.e.j);
      // cannot find symbols g.e.i and g.e.j
  }
}


// my generic class: it stores an object of a generic type
class MyGen<T> {
  T e;
  // element
  MyGen(T e) {
    this.e = e;
  }
}

class MyBase {
  int i;
  MyBase(int i) {
    this.i = i;
  }
}

class MyClass extends MyBase {
  int j;
  MyClass(int i, int j) {
    super(i);
    this.j = j;
  }
}

class MyDeriv extends MyClass {
  int k;
  MyDeriv(int i, int j, int k) {
    super(i, j);
    this.k = k;
  }
}

Saturday, February 24, 2024

Tcl socket example explained


# the source of the example code: https://www.tcl.tk/man/tcl8.5/tutorial/Tcl42.html

# paste it in a fixed width character terminal for better reading 


proc serverOpen {channel addr port} {
    puts "serverOpen: channel: $channel - from Address: $addr  Port: $port"
    puts "The default state for blocking is: [fconfigure $channel -blocking]"
    puts "The default buffer size is: [fconfigure $channel -buffersize ]"

    # Set this channel to be non-blocking.
    fconfigure $channel -blocking 0
    set bl [fconfigure $channel -blocking]
    puts "After fconfigure the state for blocking is: $bl"
 
    # Change the buffer size to be smaller
    fconfigure $channel -buffersize 12
    puts "After fconfigure buffer size is: [fconfigure $channel -buffersize ]\n"

    # When input is available, read it.
    # the script is executed at the (global level)
    #   in the interpreter in which the fileevent command was invoked
    #   the file event handler is deleted if it ever returns an error (man fileevent)
    # the event is triggered and the script is run only when the first data comes in
    # 'Server' is just a name, such that readLine can be used in other contexts, too
    fileevent $channel readable "readLine Server $channel"
}

proc readLine {who channel} {
    global didRead
    global blocked

    puts "readLine: There is input for $who on $channel"

    # on the first iteration of the while loop below there is no 'eol',
    #   the channel is in non-blocking mode, so the read fails and nothing is read, see 'man 3tcl gets'
    # on the second iteration of the 'while' loop below, this does succeed
    set len [gets $channel line]
    # the channel is non-blocking, but it may be "blocked", see 'man fblocked'
    # 1 if blocked, 0 if not blocked
    set blocked [fblocked $channel]
    puts "Characters Read: $len  Fblocked: $blocked"

    # -1 is not enough data, see 'man 3tcl gets'
    if {$len < 0} {
        if {$blocked} {
            # not enough to read
            puts "Input is blocked"
        } else {
            # the 'eof' case
            puts "The socket was closed - closing my end"
            # this closes the new channel created by 'socket -server' for the new connection
            #   the server itself is closed in the last line of the script
            close $channel;
        }
    } else {
        puts "Read $len characters:  $line"
        puts $channel "This is a return"
        flush $channel;
    }
    incr didRead;
    # puts "readLine: didRead = $didRead"
}

set server [socket -server serverOpen 33000]

# after 120 update;    # This kicks MS-Windows machines for this application

# no call for serverOpen here
# puts {before the first vwait}
# vwait didRead
# puts {after the first vwait}

# puts {before socket client}

# this sends a connection request to the server listening on port 33000
#   the server creates a (new channel) on a new port especially for this connection
#   and then it makes the client connect to this new channel
# also now the server triggers an event that will run serverOpen when processed
set sock [socket 127.0.0.1 33000]

# puts {after socket client}

# if the first vwait is commented, then serverOpen is called here
# puts {before the second vwait}
# vwait didRead
# puts {after the second vwait}

set bl [fconfigure $sock -blocking]
set bu [fconfigure $sock -buffersize]
puts "Original setting for sock: Sock blocking: $bl buffersize: $bu"

fconfigure $sock -blocking No
fconfigure $sock -buffersize 8;

set bl [fconfigure $sock -blocking]
set bu [fconfigure $sock -buffersize]
puts "Modified setting for sock: Sock blocking: $bl buffersize: $bu\n"

# Send a line to the server -- NOTE flush
set didRead 0
# this makes fileevent to trigger an event that calls lineRead when processed
puts -nonewline $sock "A Test Line"
flush $sock;

# if the first two vwait's are commented, then both serverOpen and readLine are called here
# puts {before the third vwait}
# vwait didRead
# puts {after the third vwait}

# this sends "NewLine\n" immediately after "Read 18 characters:  A Test Line"
# readLine is run only on 'wait didRead', which reads the fileevent event
#   so this iterates two times
while {$didRead < 2} {
    puts "while: didRead = $didRead"
    # Wait for didRead to be set
    vwait didRead
    if {$blocked} {
        puts $sock "Newline"
        flush $sock
        puts "SEND NEWLINE"
    }
}

# this reads the readLine "This is a return" message
set len [gets $sock line]
puts "Return line: $len -- $line"
# this closes the client socket
close $sock
# puts {before last vwait}
# this processes the last fileevent event that calls readLine for the last time
#   now readLine closes the new channel because it sees that it is closed on the client side
vwait didRead
# this closes the server, which is still listening on the 30000 port
catch {close $server}
# so 'socket' creates and manages the connection
#   similarly to a pipe or a fifo (see ~/linux/misc/bash/fifo.txt)

# 'man 3tcl gets' (three cases)
# the three non-blocking cases are:
#   successfully read
#   not enough data, returns -1 and it's blocked
#   'eof', returns -1 and it's not blocked


Friday, February 23, 2024

Tcl fileevent events explained

# paste it in a fixed width character terminal for better reading 

# do '$ touch test.txt' before you run it with '$ tclsh scriptname.tcl'

set f [open test.txt]
puts "f = $f"

set k 0
after 0 {puts "before: k = $k"}
# k is in the global space, the script is run in the global space
fileevent $f readable {incr k; puts "k = $k"}
after 500
# events are processed in the order in which they have been created
#   'vwait k' stops processing events when it finds the first k modification event
# one new fileevent event is created when fileevent is first called
#   and it is PERMANENTLY placed FIRST IN LINE in the event queue
#   this event probably creates a hook for vwait and update such that
#     two more fileevent events are created next time when
#       either the event loop is entered and there is no such a fileevent event first in the queue
#       or the queue is empty when the event loop is exited
#       these two fileevent events are placed normally last in line in the event queue
#     such a scenario is also suggested by
#       "To generate events in case of an empty queue
#       Tcl_DoOneEvent will first ask all registered event sources to setup themselves"
#       at https://tcl.sourceforge.net/c-api/notifier.html
#   error bug this is crazy and that's why it's not mentioned in man fileevent
for {set j 1} {$j<=6} {incr j} {
  puts {new for cycle}
  after 500
  after 0 {puts "before: k = $k"}
  after 500
  # update
  vwait k
  }

# update

close $f
puts "f = $f"


Sunday, January 21, 2024

Tcl 'oo::define self' explained



oo::class create c {

method a {} { puts "c a" }

self method b {} { puts "c b" }}




c create o




# this raises unknown method "a", because 'a' is a member of 'c' as a class, not as an object

# c a




# this works, because 'b' is a member of 'c' as an object, due to self, see man oo_define (^ *self)

c b




# this works, because 'a' is a member of the class 'c' that created o

o a




# this raises unknown method "b", because b is a member of c as an object, not as a class

# o b

Saturday, December 16, 2023

firefox places.sqlite tags select

copy it into a fixed width character terminal for better view 


firefox places.sqlite contains all bookmarks 


sqlite3 places.sqlite "select sql from sqlite_master 

    where tbl_name = 'moz_bookmarks' and type = 'table';" 



each bookmark has a base entry in moz_bookmarks 

    where it has the title and the fk that links to moz_places.id 

    and it has an entry with the same fk for each tag 


moz_places has an entry with id = moz_bookmarks.fk that holds the URL 

    and it has a title that usually is the same with that in moz_bookmarks 


moz_bookmarks.title is more about the page, moz_places.title is more about the site 


there is no id = 0 record in moz_bookmarks or moz_places 

    the id = 0 record is referred to signal the root of the reference chain 


in moz_bookmarks: 


a bookmark has: 

  one entry that contains its title and it's followed by 

  entries with the same fk 

      that link through their parent to one tag of that bookmark each 

      all those entries with the same fk have a null title, since this query returns no results: 

          select id, title from moz_bookmarks m where 

              (select parent from moz_bookmarks where id = m.parent) = 4 and 

                  -- this selects entries that refer tags 

                  --     because entries referred by their parent have parent = 4 

              title not null;

  type is 1 for bookmarks and their links to tags 

  position does not appear to be important, maybe it refers to the position in the displayed list 

  keyword_id is null 

  folder_type is null 

  fields after title are not relevant for the bookmarks -- tags relationship 


tags have: 

    title is the name of the tag 

    parent = 4, which is the id of the Tags folder 

    type = 2 

    fk = null 


a folder has: 

    title is the name of the folder 

    parent is the id of the parent folder 

        the root folder is the Bookmarks Menu with id = 2 

    type = 2 

    fk = null 

to select all tags of a bookmark: 

parent = 4 eliminates the folder referred in the bookmark entry that contains the title 

if there is more than one bookmark with that exact title then 

    fk = (select ...) only fits the first result 

but if you replace that '=' with 'in', then all tags of all those bookmarks are listed in one column 

  tags used more than once by different bookmarks will appear only once in the list 

sqlite> select title from moz_bookmarks where id in (select parent from moz_bookmarks where fk = (select fk from moz_bookmarks where title = 'David Icke – The Answer – full length interview. Direct no-email version – starts at 6.46 and please share with everyone you can to bypass censorship – David Icke')) and parent = 4; 

or: 

parent = 4 eliminates the folder referred in the bookmark entry that contains the title 

verified 

if there is more than one bookmark with that exact title then 

  all tags of all those bookmarks are listed in one column and 

  tags used more than once by different bookmarks will appear more than once in the list 

sqlite> select m1.title from moz_bookmarks as m1, moz_bookmarks as m2, moz_bookmarks as m3 where m3.title = 'David Icke – The Answer – full length interview. Direct no-email version – starts at 6.46 and please share with everyone you can to bypass censorship – David Icke' and m2.fk = m3.fk and m1.id = m2.parent and m1.parent = 4; 

the first version is ten times faster than the second version 

time sqlite3 places.sqlite "select title from moz_bookmarks where id in (select parent from moz_bookmarks where fk = (select fk from moz_bookmarks where title = 'David Icke – The Answer – full length interview. Direct no-email version – starts at 6.46 and please share with everyone you can to bypass censorship – David Icke')) and parent = 4;"

NWO

David Icke

politics

news

video

continue

1:00:00 continue


real 0m0.012s

user 0m0.011s

sys 0m0.001s

time sqlite3 places.sqlite "select m1.title from moz_bookmarks as m1, moz_bookmarks as m2, moz_bookmarks as m3 where m3.title = 'David Icke – The Answer – full length interview. Direct no-email version – starts at 6.46 and please share with everyone you can to bypass censorship – David Icke' and m2.fk = m3.fk and m1.id = m2.parent and m1.parent = 4;"

NWO

David Icke

politics

news

video

continue

1:00:00 continue


real 0m0.183s

user 0m0.077s

sys 0m0.105s


to select all bookmarks that have a specific tag: 

  title is not null only for the bookmark entry that contains the title. 

    we know this because this returns no lines: 

      the subquery selects the id's of all tags 

      the outer query selects all references to all tags that have not null titles 

      sqlite> select title from moz_bookmarks where 

                  parent in (select id from moz_bookmarks where parent = 4) and title is not null; 

sqlite> select id, title from moz_bookmarks where fk in (select fk from moz_bookmarks where parent = (select id from moz_bookmarks where parent = 4 and title = '1984')) and title is not null; 

sqlite> select m1.id, m1.title from moz_bookmarks m1, moz_bookmarks m2, moz_bookmarks m3 where m3.parent = 4 and m3.title = 'David Icke' and m3.id = m2.parent and m2.fk = m1.fk and m1.title not null;

select m1.id, m1.title, count(*) from moz_bookmarks m1, moz_bookmarks m2, moz_bookmarks m3 where m3.parent = 4 and m3.title = 'David Icke' and m3.id = m2.parent and m2.fk = m1.fk and m1.title not null; 

1776|What David Icke Said in 1991, Dr Michio Kaku Confirms in 2008 - YouTube|443

time sqlite3 places.sqlite "select id, title from moz_bookmarks where fk in (select fk from moz_bookmarks where parent = (select id from moz_bookmarks where parent = 4 and title = 'David Icke')) and title is not null;" 

real 0m0.011s

user 0m0.004s

sys 0m0.008s

time sqlite3 places.sqlite "select m1.id, m1.title from moz_bookmarks m1, moz_bookmarks m2, moz_bookmarks m3 where m3.parent = 4 and m3.title = 'David Icke' and m3.id = m2.parent and m2.fk = m1.fk and m1.title not null;" 

real 0m0.012s

user 0m0.008s

sys 0m0.004s


to update a tag in all bookmarks 

verified 

you can use Firefox > Library window 

  find oldtag in Search Bookmarks 

  select all found bookmarks 

  edit oldtag into newtag in Tags 

  press Enter 

or 

verified 

sqlite: 

  you need to update the parent of all entries that refer that bookmark: 

    the new tag must be already defined 

    there should be no entries that have both the old tag and the new tag at the same time 

      both these conditions can be easily configured in Firefox > Library window 

sqlite3> update moz_bookmarks set parent = (select id from moz_bookmarks where title = 'new tag' and parent = 4) where id in (select id from moz_bookmarks where parent = (select id from moz_bookmarks where title = 'old tag' and parent = 4)); 


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