Site Sponsors:
German Notation & Problematic File Names 
For years I have been popularizing the idea of using "German Notation." Formerly known as "Nazi Notation," far from conjuring-up the image of unpleasantness, I use the term whimsically; When one hears it, my hope is that we think more of "Sergent Schultz" (I know nothing!:) or "Colonel Klink" - rather than Adolph Hitler?


Ironically, in as much as standards like PEP-8 remind many software developers of the more dark-size of what being a "Nazi" was all about, the idea is that there can be far better ways to name things like variables and member functions?

Indeed, rather than blindly following the edicts of any dictator - benevolent or not - when using such a typeless language as Python, perhaps one might like to use Hungarian Notation? --Surely prefixing simple characters like a lower-case 's' for string, 'i' for integer ... or merely dropping vowels & double consonants ... can create far more succinctly-informative mnemonics?

Oh well - rather than memorize any type of rigidly defined view over how people should all be writing code the same way, by way of introducing a nice way to use keywords and built-ins as variable names, note our scattering of a simple "z" prefix around in the following code:

import os

count = 0
zRoot = "/"
print("Parsing", zRoot)
for zPath, zDirs, zFiles in os.walk(zRoot):
for zFile in zFiles:
file = os.path.join(zPath, zFile)
nodes = os.path.split(file)
for node in nodes:
if is_good_node_name(node) is False:
count += 1
print(file)
break


print("Found", count, "potential problems.")


Honoring the freedom to do what - IMHO - makes for a far better single-word mnemonic experience, allow me to complete the above example by presenting the balance of the code:

bad_chars = bytearray(":?*<>|\\/\"", "utf8")


def is_clascii(str_data):
for ss, ch in enumerate(str_data):
code = ord(ch)
if code < 32:
return False
if code > 126:
return False
return True


def is_good_node_name(str_data):
global bad_chars
str_data2 = bytearray(str_data, "utf8")
for ss, ch in enumerate(str_data2):
for ref in bad_chars:
if ref == ch:
return False
return is_clascii(str_data)


Designed to rummage around zRoot so as to find zFile that might create a problem for your cross-platform file-transferal activities (Linux? Windows? OS/X? AIX?,) my hope is that you will find the above Ptyhon3 example to be of use in planning escape attempts for our comrades in-arms in a 'Stalag near you!


Enjoy the Journey.

-Rn


[ view entry ] ( 548 views )   |  permalink  |  related link
Paginated item-picker for console listings in Python 3 
Adding to the critical mass of things that many want to do - yet cannot find a nice example on how to do - submitted for your approval please find a little class I chose to call PrintPickerList:

"""
Opportunity to support the pagination of a list so
as to allow a console user to select an item therefrom.
"""


class PrintPickerList:

def __init__(self, array=[]):
"""
Initilize the class for assignment

:return: An item with an empty list
"""
self.last_selection = -1
self.pages = array
self.page_size = 20
self.use_list(array)

def use_list(self, zlist, szpage=20):
"""
:param zlist: a list() full of string items to choose from
:param szpage: The size of the page to scroll around.
:return: True if all was well
"""
if type(zlist) is not type(self.pages):
return False
self.last_selection = -1
self.pages = zlist
self.page_size = szpage
return True

def print_header(self):
"""
An opportunity to print a column header - called once per page view
:return: Nothing
"""
pass

def print_item(self, zbss):
"""
The default row-printing logic. Feel free to use inheritance to replace
and / or otherwise update this vector as you require / desire

:param zbss: The zero-based subscript of the item to print.
:return: Nothing
"""
print("{0:02d}:\t[{1:^50}]".format(zbss+1, self.pages[zbss]))

def pick_item(self):
"""
Allow the console user to page up and down thru list,
looking for an item to select. Once selected, the
array-adjusted element number will be returned.

:return: Array-subscript selected. -1 if no item was selected.
"""
page = 0
max = len(self.pages)
if max == 0:
return -1

while True:
self.print_header()
for item in range(page, max):
nzi = item + 1
self.print_item(item)
if nzi % self.page_size == 0:
break
try:
print("p = prev, n = next, q = quit, `n` = choice")
sel = input("Enter selection: ").strip()
if sel.isnumeric():
self.last_selection = -1 # jic
sel = int(sel)

self.last_selection = sel
self.last_selection -= 1 # array is n-1
break
else:
if sel == 'p':
page -= self.page_size
if sel == 'n':
page += self.page_size
if sel == 'q':
self.last_selection = -1 # Done - no selection
break

except Exception as ex:
print(ex)

finally:
while page >= max:
page -= self.page_size
if page < 0:
page = 0

# Clean-up the results:
if self.last_selection >= max:
self.last_selection = max - 1
if self.last_selection is not -1 and self.last_selection < 0:
self.last_selection = 0
return self.last_selection


if __name__ == '__main__':
doc = list()
for ref in range(100):
doc.append("Selection number" + str(ref))
pager = PrintPickerList()
if pager.use_list(doc) is False:
print("Big problem")
exit(-1)
sel = pager.pick_item()
selected = "No item selected."
if sel is not -1:
selected = doc[sel]
print("You selected '" + selected + "'")

The 'docstrings pretty much say it all. Yet allow us to note that we can paginate many other types - as well print column headers - by either updating, and / or inheriting + overriding:

    def print_header(self):
pass

def print_item(self, zbss):
print("{0:02d}:\t[{1:^50}]".format(zbss+1, self.pages[zbss]))

So if you have ever wanted to allow a user to scroll thru a large list of items - certainly if that list is far too large to readily fit on the screen - then you might enjoy putting PrintPickerList to work in your own Pythonic masterpieces. --It's 'kinda like having a more++ for use from within the Python console 'ui.


Enjoy the journey,

-Rn




BlogBlock[Python-Advanced-Classes]

[ view entry ] ( 562 views )   |  permalink
Fast & Easy: Managing SQL Data in Python 3! 
While serving as the Principal Software Development Engineer at Informix, I wrote several articles for BYTE Magazine. Aside from coining the term "DLL Hell" in 1991, I was honoured to work with the same teams that created the Wingz Spreadsheet, as well as what remains the fastest databases on the planet.

Believe it or leave it, for we storage-access enthusiasts times have not changed very much since those days. What has changed has been the massively cool way that we can EASILY add a free SQL Database to our applications.

Database Arsenal: SQL


While I have grown very fond of Microsoft's LINQ, Hibernate, Spring, and even MyBatis, to date nothing comes even close to the quick-and-easy way that we can add the power of SQL to our Pythonic undertakings.

To convince any nay-sayers, submitted for your approval please try out the following 'nifty little demonstration program:

#!/usr/bin/env python3
import sqlite3
""" Log arbitrary "two string" information to an sqlite3 database """


class LogDB:

def __init__(self):
self.bOpen = False

def open(self):
""" Connect to the LOCAL database """
if self.bOpen == True:
return
self.conn = sqlite3.connect('PyLog.sqlt3')
self.curs = self.conn.cursor()
self.bOpen = True

def createTable(self):
""" Create a table for the logged messages """
self.open()
cmd = 'create table logged \
(timestr char(20), message char(256))'
self.curs.execute(cmd)
self.close()

def dropTable(self):
""" Remove the table from the database """
self.open()
cmd = 'drop table logged'
self.curs.execute(cmd)
self.close()

def insertRow(self, timestr, message):
""" Insert an arbitrary logge prefix & message """
self.curs.execute('insert into logged values(?,?)', [timestr, message])

def selectMessages(self):
""" Generator to enumerate thru selected values """
self.curs.execute('select * from logged')
for tstr, msg in self.curs.fetchall():
yield tstr, msg

def close(self):
""" Safe coding is no accident ... """
if self.bOpen:
self.conn.commit()
self.bOpen = False

if __name__ == "__main__":
db = LogDB()
db.createTable()
try:
db.open()
for ss in range(10):
db.insertRow("MyTime" + str(ss), "Message " + str(ss + 1))
for zt, mgs in db.selectMessages():
print(zt, mgs)
finally:
db.close()
db.dropTable()

Designed for more than re-use under SQLite & built around the simple SQL concepts of CREATE TABLE, Insert Data ("row"), Read Row, and DROP TABLE, about the only things lacking in the above is the (1) Update Row (not important in the logging metaphor), as well as (2) a way to unlink() the external database file itself.

The "Pick Two" Dilemma


The above demonstration was also designed for fast & inexpensive data collection activities. In order to satisfy the pedantic, we must therefore surely take a moment to note also that - whenever we plan to manage such entries - for example in relation to another set of database tables - that (3) adding a unique, auto-generated primary key is also recommended.

Come to that, also note how parsing & normalizing data (such as the date & time) might also be something to consider when (4) aggregating these rapidly-collected data into an enterprise schema. (Hence the grand division between "time," "quality" and "cost" for data collection activities in the database world.... but that is another story!)

So while knowing something is great, more than ever before in our modern times have far too many discovered that knowing when to use it (i.e. "pick 2:3") is often quite another story!

It is a "knowledge" (i.e. showing off what we know) versus "wisdom" (showing off how well our product works) type-of thing.


Enjoy the journey,

-Rn




BlogBlock[Python-Advanced-Classes]

[ view entry ] ( 698 views )   |  permalink  |  related link

<<First <Back | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Next> Last>>