Saturday, 29 January 2011

Windows command prompt zip support

I've been writing a script to fetch and build a set of dependencies, and trying to keep it simple. But SDL includes the Visual C project and solution files in a zip file. This is a problem because Windows does not have command line zip file support. The point of this exercise is to just get the job done, not to add other new dependencies.

Something in Windows that jumps out when you have this need, is that there is support for compressed folders. In an Explorer window, you can simply double click on a zip archive and treat it like any other folder. Surely there must be a way to access this functionality from the command line..


My first port of call was Powershell. This comes with later versions of Windows, and shouldn't be an unreasonable dependency - surely it has zip file support? No, this is not the case. But it turns out someone used COM object support to access the shell and work with Explorer.  Unfortunately, this was a false lead.  Powershell lives in its own bubble where scripts need to be signed, to be executed behind the scenes as part of some abstract compilation process.  It isn't acceptable for me to say, go into Powershell and turn off this script security setting that requires signing.  That's worse than adding a dependency, it's a strange incomprehensible complication.  Not doing it gives this lovely error, but it probably gives it to you in equally comprehensible English.


At this point I thought, you know, vbscript never had this problem.  So I searched for "wscript", "zip" and assorted other keywords and came across this script which did exactly the same as the Powershell script, but in straightforward and directly usable vbscript.  Further searching of course was a reminder that all the useful answers are available on the Stack Overflow family of sites, in this case Server Fault.

Problem solved. Of course, nothing comes for free. This is an Explorer action, so copying from a zip folder to another folder, will pop up a file transfer dialog with a progress bar for the duration. However, that is a small price to pay for simplicity.

Friday, 28 January 2011

Proxying object access

Why are you reading this post? You are wasting valuable time where you could be writing my code for me! On that note, I often write the following code pattern. Anyone know of a library somewhere which has a variety of simple and decoupled helper code like this?

class ObjectWrapper(object):
def __init__(self, ob, attrWrapperClass=None):
self.__attr_wrapper__ = attrWrapperClass
self.__wrapped_object__ = ob

def __getattr__(self, attrName):
# This will trigger an attribute error, if it does not exist.
realValue = getattr(self.__wrapped_object__, attrName)
# We give them the attribute directly, if it is not callable.
if not callable(realValue):
return realValue
# Otherwise, all calls should be proxied and resources tracked appropriately.
attrWrapperClass = self.__attr_wrapper__
if attrWrapperClass is None:
attrWrapperClass = ObjectAttributeWrapper
return attrWrapperClass(self.__wrapped_object__, attrName)

class ObjectAttributeWrapper(object):
__bypass_attrnames__ = set()

def __init__(self, ob, obAttrName):
self.__wrapped_object__ = ob
self.__wrapped_attrname__ = obAttrName

@property
def __value__(self):
return getattr(self.__wrapped_object__, self.__wrapped_attrname__)

@property
def __context__(self):
return "%r.%s" % (self.__wrapped_object__, self.__wrapped_attrname__)

def __getattr__(self, subAttrName):
# Allow introspection.
if subAttrName in self.__bypass_attrnames__ or subAttrName.startswith("im_") or subAttrName.startswith("func_"):
return getattr(self.__value__, subAttrName)
return AttributeError("Not expecting to be asked about '%s' for '%r.%s'" % (subAttrName, self.__context__))

def __call__(self, *args, **kwargs):
""" Wrap the call of a method with stat tracking. """
with StatContext_NEVER_CHECK_THIS_IN(self.__context__):
return self.__value__(*args, **kwargs)
In the use case for this particular code, CPU usage and memory allocations within each call made on the wrapped instance are tagged with label comprised of the object representation and the function name. This is of course not the most ideal label to tag it with, but for the purpose of pasting here it is good enough.

For context, just this morning I used it in the following way:
class SomeObject(object):
def __init__(self):
self.log = logging.getLogger("blah")
try:
from . import stats
self.log = stats.ObjectWrapper(self.log)
except ImportError:
pass
With the following output:

Hands up who has a customised xreload.py

I was rereading this comment on my blog, where Hanno said:

Nice to see someone else experimenting with reliable code reload. I have my own version of Guido's original work at http://svn.plone.org/svn/plone/plone.reload/trunk/plone/reload/xreload.py
You know what, I use a customised version of this module as well (admittedly at work). Shouldn't we¹ gather together all the customised versions of these modules, and collect the improvements? Who's with me? Bueller?... Bueller?... Bueller? If anyone has a version which they can link to, maybe throw a comment pointing to it on this post.

[¹] When I say we, I mean someone else who revels in doing work that other people suggest they do. But should there be a range of versions with interesting changes, then I might gather them into work's version and release the result.