The module system in fairly rich, where the import keyword is really only the tip of the iceberg. In today’s post, I’m going to go through a very simple dynamic module loading unit.
A module loader allows you to invoke pieces of code dynamically at run-time. Configurations of what gets executed when can be defined in a database, statically, where ever. What’s important is that we’ll reference our modules by name (using a string), have them loaded dynamically and then executed.
As a quick aside, my use of the term module throughout this article could refer to a python module; it could also refer to a small dynamic piece of code I’m calling a module.
Common module format
To get started, we really need to settle on a common format or structure that our modules will take. It’ll be this assumption that our host object will use to uniformly invoke these pieces of code. Immediately, this format has two major problems that need to be solved for this system to work. It needs to:
Provide a construction interface
Provide runnability
There are plenty of other things that we could add in:
Event for when the module is loaded and torn down
Top-level error handler for when exceptions bubble out of the module
Common logging framework
For the purposes of this article, we’ll focus on loading and executing the module.
What is a module?
For our implementation, we’re going to say that a module is a class. Making this decision to create a module as a class allows us to refer to our module as a definition (the actual class itself) and defer the instancing of our objects to the class’s construction invocation.
A very simple module might look like this:
classModule:def__init__(self,state):self.state=statedefrun(self):print"This is module1 doing its thing"
You can see that our constructor is taking in a parameter called state. There’s no real significance here aside from giving the module system the ability to send arbitrary state information during the instantiation process. The run function is what our host will be executing to perform the module’s work.
Factory construction
The factory pattern allows a developer to encapsulate the construction of related types inside of a function (or factory implementation class), and have this construction derived at run-time or configured elsewhere (think inversion-of-control). We’re going to borrow very shallowly from this concept.
Each module that participates on our framework must export a create function. This function can take parameters; so long as all of your factory constructors define the same interface it doesn’t matter. For today’s example, my create function takes an arbitrary object called state which just allows the implementing developer to send information to the constructed module:
defcreate(state):returnModule(state)
The host
The host’s job is to:
Load a module (a python file) off disk
import it
Call the module factory create
Call the run method of the module
There’s a lot more fancy stuff that we could do of course. Going back to the start of this article, there are lots of different services that the host should be able to offer each module that gets loaded to provide the overall system a richer experience without re-writing common services. Logging, error handling, network and data connections could be simplified in the framework to provide a quick avenue to modules to be productive!
Our very simple host, would look something like this:
The heart of the host really is the run_module function and it leans heavily on the __import__ call to get its job done. The state parameter for the module is wasted in this context, but you can see how it’d be relatively easy to manage context aware state per process that you’re running.
The run method runs our module code.
Conclusion
This is just a simple, dynamic module loader. It can be applied in a lot of highly complex scenarios but the basic principles of keeping modules small, concise should help you not get ahead of yourself.
The collections library included with python has some very helpful utilities to make your programming life a little easier. In today’s post, I’m going to go through a few of them.
Named tuple
This is really the feature that brought my attention to this library, initially. Where a tuple is an immutable set of values that are unnamed, you can create a class using the namedtuple() function to bring a little more formality to your types:
importcollectionsPerson=collections.namedtuple('Person',['firstName','lastName','age'])joe=Person("Joe","Smith",21)# joe is now as follows
Person(firstName='Joe',lastName='Smith',age=21)
That’s a neat shortcut.
Counter
A Counter class is a dict object that when queried for a key that doesn’t exist, will return a 0; and create that item ready for counting.
animals=['dog','cat','cat','bat','mouse','dog','elephant']c=collections.Counter()foranimalinanimals:c[animal]+=1# "c" now looks like this
# Counter({'dog': 2, 'cat': 2, 'bat': 1, 'elephant': 1, 'mouse': 1})
Pretty handy.
deque
A basic stack or queue like data structure can be initialized with the use of the deque class. As this object does look a lot like a list, it’s important to remember why it exists:
Though list objects support similar operations, they are optimized for fast fixed-length operations and incur O(n) memory movement costs for pop(0) and insert(0, v) operations which change both the size and position of the underlying data representation.
This tells us that some internal implementation assumptions have been made to tailor the runtime usecase of this class specifically for statically sized queues.
In today’s post, I’m going to go through some basic concepts of the language.
Classes
For our example, we’ll define a Player class. This will hold our player’s name, height and weight which won’t change once we set them. Note that we’re using the val keyword in the parameter list of the default constructor for the class. This automatically generates immutable members for us accessing this information.
classPlayer(valname:String,valheight:Int,valweight:Int){defgetMessage():String="Game on!"deftalk():Unit={valmessage=this.getMessage()println(s"$name the player says '$message'")}}
We’ve also given our player the ability to talk. The player also has a message to say with getMessage.
Inheritance
We can inherit from this base Player class and define a Forward and a Back.
classForward(name:String,height:Int,weight:Int)extendsPlayer(name,height,weight){overridedefgetMessage():String="Uggg!"}classBack(name:String,height:Int,weight:Int)extendsPlayer(name,height,weight){overridedefgetMessage():String="How does my hair look?"}
Forwards and backs say different things, so we have overridden the default getMessage implementation in each case.
Traits
A trait is similar to the interface that you’d find in other languages. The main difference to a strict interface, is that a trait can have implementation. In the following example, the ValueEmitter trait is applied to different types of objects, but it commonly utilised to equate an answer.
traitValueEmitter{defvalue():Double}
To represent a literal value and an operation both using this trait, we apply it to classes:
This syncs up really well with the pattern matching ideas.
Pattern Matching
Following on with the example in Case Classes, we’ll write a function that uses pattern matching to ensure we’re getting the correct type through. Also see that we can pattern match on the values being passed through; not just the type.
defcalculate(v:ValueEmitter):Double=vmatch{caseLiteralValue(lv)=>lvcaseOperation(v1,v2,"/")=>{thrownewException("I do not support divide")}caseOperation(v1,v2,op)=>{valleft=calculate(v1)valright=calculate(v2)opmatch{case"+"=>left+rightcase"-"=>left-rightcase"*"=>left*rightcase"/"=>left/rightcasedefault=>0}}}
Object
Static classes (or singleton objects) are just a way of defining single-use classes. You’ll see main sitting within an object definition rather than seeing main declared statically.
Both transactionDb and objectStoreDb become accessible when prefixed with Config..
Accessors
You can short cut the creation of your accessors using your default constructor. As you’d expect, you use val for immutable, read-only properties and var for the read/write items.
classStockPrice(valcode:String,varprice:Double){}
The code on the stock doesn’t change but its price does.
These accessors can be defined manually using the following convention; this also allows you to specify any code that needs to execute within these accessors:
The information_schema in PostgreSQL holds a lot of really handy views with information about the current database. Very useful in investigation and discovery scenarios.
In today’s post, we’ll go through the tables that sit in this schema and how they can help. The information_schema documentation can be found here and is what this article has been based on.
Meta and Context
-- get the current database nameSELECT*FROMinformation_schema.information_schema_catalog_name;-- what are the roles does the current user have that the admin option for?SELECT*FROMinformation_schema.administrable_role_authorizations;-- what roles are applicabl to the current user?SELECT*FROMinformation_schema.applicable_roles;-- attributes on composite data types that the current user has access toSELECT*FROMinformation_schema.attributes;
Server
-- available character setsSELECT*FROMinformation_schema.character_sets;-- list all collations available to this databaseSELECT*FROMinformation_schema.collations;-- lists the available character sets that apply to the collationsSELECT*FROMinformation_schema.collation_character_set_applicability;-- list all of the options defined for foreign-data wrappersSELECT*FROMinformation_schema.foreign_data_wrapper_options;-- list all foreign-data wrappers defined in the databaseSELECT*FROMinformation_schema.foreign_data_wrappers;-- lists all of the options defined for foreign servers in this databaseSELECT*FROMinformation_schema.foreign_server_options-- lists all of the standard sql features supportedSELECT*FROMinformation_schema.sql_features;-- lists features that are implementation definedSELECT*FROMinformation_schema.sql_implementation_info;-- lists all of the sql languages supportedSELECT*FROMinformation_schema.sql_languages;-- lists all of the sql defined feature packages are supportedSELECT*FROMinformation_schema.sql_packages;-- lists all of the supported parts of the sql standardSELECT*FROMinformation_schema.sql_parts;-- lists the size limits in the databaseSELECT*FROMinformation_schema.sql_sizing;-- lists sizing profile informationSELECT*FROMinformation_schema.sql_sizing_profiles;-- lists all of the foreign servers defined in this databaseSELECT*FROMinformation_schema.foreign_servers;-- lists all of the options defined for foreign tables in this databaseSELECT*FROMinformation_schema.foreign_table_options;-- lists all of the foreign tables SELECT*FROMinformation_schema.foreign_tables;-- list all settings for user mappingsSELECT*FROMinformation_schema.user_mapping_options;-- list all user mappings SELECT*FROMinformation_schema.user_mappings;
Catalog
-- list all check constraintsSELECT*FROMinformation_schema.check_constraints;-- lists all of the parameters to functions in the databaseSELECT*FROMinformation_schema.parameters;-- lists all foreign keys in the databaseSELECT*FROMinformation_schema.referential_constraints;-- lists all of the functions in the databaseSELECT*FROMinformation_schema.routines;-- lists all of the sequencesSELECT*FROMinformation_schema.sequences;-- lists all constraints from tables in this databaseSELECT*FROMinformation_schema.table_constraints;-- list all tablesSELECT*FROMinformation_schema.tables;-- list all triggersSELECT*FROMinformation_schema.triggers;-- list all composite typesSELECT*FROMinformation_schema.user_defined_types;-- lists all views in the databaseSELECT*FROMinformation_schema.views;-- list all transforms (9.5 ONLY)SELECT*FROMinformation_schema.transforms;
Security and Privileges
-- list all columns and their priviledgesSELECT*FROMinformation_schema.column_privileges;-- lists all privileges on columnsSELECT*FROMinformation_schema.role_column_grants;-- lists all privileges on functionsSELECT*FROMinformation_schema.role_routine_grants;-- lists all privileges on tablesSELECT*FROMinformation_schema.role_table_grants;-- lists all privileges on udfsSELECT*FROMinformation_schema.role_udt_grants;-- lists all privileges on various objects SELECT*FROMinformation_schema.role_usage_grants;-- lists all privileges on functionsSELECT*FROMinformation_schema.routine_privileges;-- lists all of the table privileges SELECT*FROMinformation_schema.table_privileges;-- list all udt privilegesSELECT*FROMinformation_schema.udt_privileges;-- list privileges on various objectsSELECT*FROMinformation_schema.usage_privileges;-- list all data types that the user has access toSELECT*FROMinformation_schema.data_type_privileges;-- list all enabled rolesSELECT*FROMinformation_schema.enabled_roles;
Explore
-- list all routines that are used by a check constraintSELECT*FROMinformation_schema.check_constraint_routine_usage;-- list columns using a domain defined inside of this databaseSELECT*FROMinformation_schema.column_domain_usage;-- list all columns that use types owned by the current userSELECT*FROMinformation_schema.column_udt_usage;-- list all columns used by constraintsSELECT*FROMinformation_schema.constraint_column_usage;-- list all tables used by constraintsSELECT*FROMinformation_schema.constraint_table_usage;-- list all domains based on data types owned by the current userSELECT*FROMinformation_schema.domain_udt_usage;-- lists all columns in the database restricted by primary,unique, foreign or check constraintSELECT*FROMinformation_schema.key_column_usage;-- list all columns that are used in viewsSELECT*FROMinformation_schema.view_column_usage;-- list all routines that are used in viewsSELECT*FROMinformation_schema.view_routine_usage;-- lists all tables that are used in viewsSELECT*FROMinformation_schema.view_table_usage;-- list all of the columns in the databaseSELECT*FROMinformation_schema.columns;-- list all triggers that specify update columnsSELECT*FROMinformation_schema.triggered_update_columns;-- list options for any foreign table columnsSELECT*FROMinformation_schema.column_options;-- list all constraints that belong to domains in the current databaseSELECT*FROMinformation_schema.domain_constraints;-- list all domains defined in the databaseSELECT*FROMinformation_schema.domains-- list all of the data types inside of array elementsSELECT*FROMinformation_schema.element_types;-- lists all of the schemas SELECT*FROMinformation_schema.schemata;
Today’s post is a quick tip on X11 port forwarding, and how to use it to run X11 applications remotely.
The setup
Your remote computer, the one that will actually run the application needs openssh installed. Use your favorite package manager to get that installed. You then need to edit your sshd configuration file to allow X11 port forwarding.
sudo emacs /etc/ssh/sshd_config
You need to make two edits to this file:
X11Forwarding yes
X11UseLocalhost no
Restart the ssh daemon.
Running
From your client computer now, connect to your remote host and run any X11 application that you want. It’ll appear on your client machine.