Home Page
Archive > Posts > Tags > Python
Search:

Bullet Help Formatter for Python’s argparse
This is a HelpFormatter for Python’s argparse class which:
  • Takes raw input and wraps long lines to indent against the current line start.
  • When an indented/list line is encountered, which starts with spaces followed by a star "*", wrapped line’s indents will start 2 spaces after the star.
  • Lines attempt to split at words of 10 characters or less (see .MinCharsInSplitWord).
  • If a line needs to split along a word longer than this, a hyphen is inserted at the end of the line.

import argparse
import re
class BulletHelpFormatter(argparse.HelpFormatter):
    def __init__(self, *args, **kwargs):
        super(BulletHelpFormatter, self).__init__(*args, **kwargs)
        self.MinCharsInSplitWord=10

    def _split_lines(self, text, width):
        #Split lines around line breaks and then modify each line
        Lines=[]
        for Line in text.splitlines():
            #Get the number of spaces to put at subsequent lines
            #0 if not a list item, oherwise, 2+list item start
            ListEl=re.match(r'^ *\*', Line)
            NumBeginningSpace=(0 if ListEl==None else ListEl.end()+1)

            #Add extra spaces at the beginning of each line to match the start of the current line, and go to a maxium of $width
            IsFirstPass=True
            SpacesToAdd=''
            NumSpacesToAdd=0
            while(True):
                #Get the word break points before and after where the line would end
                MaxLineLen=max(min(width-NumSpacesToAdd, len(Line)), 1)
                PrevWordBreak=CurWordBreak=0
                for WordBreak in re.finditer(r'(?<=\W).|\W|$', Line):
                    PrevWordBreak=CurWordBreak
                    CurWordBreak=WordBreak.start()
                    if CurWordBreak>=MaxLineLen:
                        if CurWordBreak==MaxLineLen:
                            PrevWordBreak=CurWordBreak
                        break

                #If previous wordbreak is more than MinCharsInSplitWord away from MaxLineLen, then split at the end of the line
                IsSplit=(PrevWordBreak<1 or CurWordBreak-PrevWordBreak>self.MinCharsInSplitWord)
                SplitPos=(MaxLineLen if IsSplit else PrevWordBreak)

                #Append the new line to the list of lines
                Lines.append(SpacesToAdd+Line[0:SplitPos]+('-' if IsSplit else ''))
                Line=Line[SplitPos:]

                #If this is the end, nothing left to do
                if len(Line)==0:
                    break

                #If this is the first pass, update line creation variables
                if IsFirstPass:
                    IsFirstPass=False
                    NumSpacesToAdd=NumBeginningSpace
                    SpacesToAdd=(' ' * NumSpacesToAdd)

        return Lines
Ping URL
Cause Python is quick to program in and can make executables

The following is a Python script that automatically pings a requested web address at a given interval. It was made as a quick favor for a friend. Here is the downloadable source code and Windows binary.

The Configuration Options File (PingURL.cfg) contains 2 lines:
  1. The URL to ping (The default pings the GetIP script)
  2. The millisecond interval between pings (Default=600000=10 minutes)

#!python
from sys import stderr
from urllib import urlopen
from time import localtime, strftime, sleep

#Main function
def Main():
    #Open the settings file
    SettingFileName='PingURL.cfg';
    Settings=[] #Blank out settings file variable in case it can't be opened
    try:
        Settings=open(SettingFileName, 'r').readlines()
    except IOError as (errno, strerror):
        stderr.write('Cannot open {0} configuration file: I/O error({1}): {2}\n'.format(SettingFileName, errno, strerror))
        return

    #Confirm valid settings were passed
    if(len(Settings)<2):
        stderr.write('Not enough settings found in settings file\n')
        return
    try:
        IntervalTime=int(Settings[1])
    except:
        stderr.write('Invalid interval time\n')
        return
        
    #Ping the URL indefinitely
    while(True):
        try:
            URLText=urlopen(Settings[0]).read()
        except:
            URLText='READ FAILED'
        print 'URL Pinged At {0}: {1}'.format(strftime('%Y-%m-%d %H:%M:%S', localtime()), URLText)
        sleep(IntervalTime/1000)

#Run the program
Main()
Python Pros and Cons
Just another language
I am a bit disappointed in Python after this project for many reasons:
  • Windows support is lacking. The PyWin32 helps fill this gap, but it itself is missing many API calls, doesn’t support Unicode (from what I can find), and has next to no documentation (besides samples).
  • Starting with Python 2.6, executables are compiled differently and include manifests, which cause some major annoying (and quite undocumented) problems with DLLs that are very unintuitive to fix. I ended up including a manifest and DLL from the “windows/system32” directory in the distribution to fix this.
  • Interfacing with (C style) shared objects (Windows DLLs and probably Unix Shared Objects) is clunky, especially when structures are involved.
  • Documentation on many of the standard Python modules is very lacking. After having recently learned Perl, and dealing with its wonderful documentation, this is a bit disappointing. I might be missing something through, because Python is supposed to be able to naturally document itself through comments after function headers...
  • While inheritance and classes themselves are implemented well, I find the way JavaScript does classes (objects) much easier to work with and more robust. It’s great being able to access any object/class element as both a member “Object.MemberName” or an index “Object['MemberName']”. This also, I think, has a lot to do with the fact that Python is [dynamically] typed, which is wonderful. But from the way the language seems to work (I would need to do more testing), this kind of thing seems like it could easily be implemented. I really just don’t like how lists, dictionaries, and classes are so separated. It’s much more useful how both PHP and JavaScript combine them into one concept.
  • Even if the language is dynamically typed to help catch errors more naturally, there are other things in the language that can make errors harder to catch, like how variable lookup is done through the whole function stack instead of just at a global and local level.
  • I find the separation of tuples and lists unneeded. Perl does it more naturally, and in one concept, through dereferencing arrays into lists.

There are many great ideas and implementations in the language though that are wonderful to work with including:
  • Parameters can be passed, at the same time, through both named parameters and a list of parameters, and can then be retrieved as parameters, lists, and dictionaries.
  • Unicode support for [probably] all encodings is natively supported. Strings are very easy to work with, even as ASCII. The best part is Python3 (which I have not tinkered with yet) reportedly improved the implementations even more by separating strings into always-Unicode, and binary data (instead of thinking of it as ASCII).
  • As mentioned above, it is a [dynamically] typed language, which is great for larger projects.
  • Different number types (floats, ints, unsigned ints, large numbers, etc) work naturally together and extend as they need to. While this gives the language a hit on speed, it does make it very usable.