diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py
old mode 100755
new mode 100644
index 9093c22f..9c14d16f
--- a/pyfpdb/Configuration.py
+++ b/pyfpdb/Configuration.py
@@ -59,28 +59,44 @@ def get_exec_path():
return sys.path[0]
def get_config(file_name, fallback = True):
- """Looks in exec dir and in self.default_config_path for a config file."""
- config_path = os.path.join(DIR_SELF, file_name) # look in exec dir
- if os.path.exists(config_path) and os.path.isfile(config_path):
- return config_path # there is a file in the exec dir so we use it
- else:
- config_path = os.path.join(DIR_CONFIG, file_name) # look in config dir
- if os.path.exists(config_path) and os.path.isfile(config_path):
+ """Looks in cwd and in self.default_config_path for a config file."""
+ exec_dir = get_exec_path()
+ config_path = os.path.join(exec_dir, file_name)
+# print "config_path=", config_path
+ if os.path.exists(config_path): # there is a file in the cwd
+ return config_path # so we use it
+ else: # no file in the cwd, look where it should be in the first place
+ default_dir = get_default_config_path()
+ config_path = os.path.join(default_dir, file_name)
+# print "config path 2=", config_path
+ if os.path.exists(config_path):
return config_path
# No file found
if not fallback:
return False
-# OK, fall back to the .example file, should be in the exec dir
- if os.path.exists(os.path.join(DIR_SELF, file_name + ".example")):
+# OK, fall back to the .example file, should be in the start dir
+ if os.path.exists(file_name + ".example"):
try:
- shutil.copyfile(os.path.join(DIR_SELF, file_name + ".example"), os.path.join(DIR_CONFIG, file_name))
- print "No %s found, using %s.example.\n" % (file_name, file_name)
- print "A %s file has been created. You will probably have to edit it." % os.path.join(DIR_CONFIG, file_name)
- log.error("No %s found, using %s.example.\n" % (file_name, file_name) )
+ print ""
+ if not os.path.isdir(default_dir):
+ msg = "Creating directory: '%s'" % (default_dir)
+ print msg
+ logging.info(msg)
+ os.mkdir(default_dir)
+ shutil.copyfile(file_name + ".example", config_path)
+ msg = "No %s found in %s or %s\n" % (file_name, exec_dir, default_dir) \
+ + "Config file has been created at %s.\n" % config_path \
+ + "Edit your screen_name and hand history path in the supported_sites "\
+ + "section of the \nPreferences window (Main menu) before trying to import hands."
+ print msg
+ logging.info(msg)
+ file_name = config_path
except:
- print "No %s found, cannot fall back. Exiting.\n" % file_name
+ print "Error copying .example file, cannot fall back. Exiting.\n"
+ sys.stderr.write("Error copying .example file, cannot fall back. Exiting.\n")
+ sys.stderr.write( str(sys.exc_info()) )
sys.exit()
else:
print "No %s found, cannot fall back. Exiting.\n" % file_name
@@ -94,26 +110,18 @@ def get_logger(file_name, config = "config", fallback = False):
try:
logging.config.fileConfig(conf)
log = logging.getLogger(config)
+ log.debug("%s logger initialised" % config)
return log
except:
pass
log = logging.basicConfig()
log = logging.getLogger()
- log.error("basicConfig logger initialised")
+ log.debug("config logger initialised")
return log
-def check_dir(path, create = True):
- """Check if a dir exists, optionally creates if not."""
- if os.path.exists(path):
- if os.path.isdir(path):
- return path
- else:
- return False
- if create:
- print "creating directory %s" % path
- else:
- return False
+# find a logging.conf file and set up logging
+log = get_logger("logging.conf")
########################################################################
# application wide consts
@@ -121,32 +129,20 @@ def check_dir(path, create = True):
APPLICATION_NAME_SHORT = 'fpdb'
APPLICATION_VERSION = 'xx.xx.xx'
-DIR_SELF = get_exec_path()
-DIR_CONFIG = check_dir(get_default_config_path())
-DIR_DATABASE = check_dir(os.path.join(DIR_CONFIG, 'database'))
-DIR_LOG = check_dir(os.path.join(DIR_CONFIG, 'log'))
-
DATABASE_TYPE_POSTGRESQL = 'postgresql'
DATABASE_TYPE_SQLITE = 'sqlite'
DATABASE_TYPE_MYSQL = 'mysql'
-#TODO: should this be a tuple or a dict
DATABASE_TYPES = (
DATABASE_TYPE_POSTGRESQL,
DATABASE_TYPE_SQLITE,
DATABASE_TYPE_MYSQL,
)
-# find a logging.conf file and set up logging
-log = get_logger("logging.conf", config = "config")
-log.debug("config logger initialised")
-
-# and then log our consts
-log.info("DIR SELF = %s" % DIR_SELF)
-log.info("DIR CONFIG = %s" % DIR_CONFIG)
-log.info("DIR DATABASE = %s" % DIR_DATABASE)
-log.info("DIR LOG = %s" % DIR_LOG)
-NEWIMPORT = True
-LOCALE_ENCODING = locale.getdefaultlocale()[1]
+#LOCALE_ENCODING = locale.getdefaultlocale()[1]
+LOCALE_ENCODING = locale.getpreferredencoding()
+if LOCALE_ENCODING == "US-ASCII":
+ print "Default encoding set to US-ASCII, defaulting to CP1252 instead -- If you're not on a Mac, please report this problem."
+ LOCALE_ENCODING = "cp1252"
########################################################################
def string_to_bool(string, default=True):
@@ -428,7 +424,8 @@ class Config:
if file is not None: # config file path passed in
file = os.path.expanduser(file)
if not os.path.exists(file):
- log.error("Specified configuration file %s not found. Using defaults." % (file))
+ print "Configuration file %s not found. Using defaults." % (file)
+ sys.stderr.write("Configuration file %s not found. Using defaults." % (file))
file = None
if file is None: file = get_config("HUD_config.xml", True)
diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py
index 5cd25d9d..54690979 100644
--- a/pyfpdb/Database.py
+++ b/pyfpdb/Database.py
@@ -39,41 +39,38 @@ import string
import re
import Queue
import codecs
-import logging
import math
# pyGTK modules
+# FreePokerTools modules
+import SQL
+import Card
+import Tourney
+import Charset
+from Exceptions import *
+import Configuration
+log = Configuration.get_logger("logging.conf","db")
+
+
# Other library modules
try:
import sqlalchemy.pool as pool
use_pool = True
except ImportError:
- logging.info("Not using sqlalchemy connection pool.")
+ log.info("Not using sqlalchemy connection pool.")
use_pool = False
try:
from numpy import var
use_numpy = True
except ImportError:
- logging.info("Not using numpy to define variance in sqlite.")
+ log.info("Not using numpy to define variance in sqlite.")
use_numpy = False
-# FreePokerTools modules
-import Configuration
-import SQL
-import Card
-import Tourney
-import Charset
-from Exceptions import *
-
-log = Configuration.get_logger("logging.conf", config = "db")
-log.debug("db logger initialized.")
-encoder = codecs.lookup('utf-8')
-
DB_VERSION = 119
@@ -247,13 +244,14 @@ class Database:
# connect to db
self.do_connect(c)
- print "connection =", self.connection
+
if self.backend == self.PGSQL:
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE
#ISOLATION_LEVEL_AUTOCOMMIT = 0
#ISOLATION_LEVEL_READ_COMMITTED = 1
#ISOLATION_LEVEL_SERIALIZABLE = 2
+
if self.backend == self.SQLITE and self.database == ':memory:' and self.wrongDbVersion:
log.info("sqlite/:memory: - creating")
self.recreate_tables()
@@ -374,20 +372,20 @@ class Database:
print msg
raise FpdbError(msg)
elif backend == Database.SQLITE:
- logging.info("Connecting to SQLite: %(database)s" % {'database':database})
+ log.info("Connecting to SQLite: %(database)s" % {'database':database})
import sqlite3
if use_pool:
sqlite3 = pool.manage(sqlite3, pool_size=1)
else:
- logging.warning("SQLite won't work well without 'sqlalchemy' installed.")
+ log.warning("SQLite won't work well without 'sqlalchemy' installed.")
if database != ":memory:":
if not os.path.isdir(self.config.dir_databases):
print "Creating directory: '%s'" % (self.config.dir_databases)
- logging.info("Creating directory: '%s'" % (self.config.dir_databases))
+ log.info("Creating directory: '%s'" % (self.config.dir_databases))
os.mkdir(self.config.dir_databases)
database = os.path.join(self.config.dir_databases, database)
- logging.info(" sqlite db: " + database)
+ log.info(" sqlite db: " + database)
self.connection = sqlite3.connect(database, detect_types=sqlite3.PARSE_DECLTYPES )
sqlite3.register_converter("bool", lambda x: bool(int(x)))
sqlite3.register_adapter(bool, lambda x: "1" if x else "0")
@@ -397,7 +395,10 @@ class Database:
if use_numpy:
self.connection.create_aggregate("variance", 1, VARIANCE)
else:
- logging.warning("Some database functions will not work without NumPy support")
+ log.warning("Some database functions will not work without NumPy support")
+ self.cursor = self.connection.cursor()
+ self.cursor.execute('PRAGMA temp_store=2') # use memory for temp tables/indexes
+ self.cursor.execute('PRAGMA synchronous=0') # don't wait for file writes to finish
else:
raise FpdbError("unrecognised database backend:"+backend)
@@ -412,7 +413,7 @@ class Database:
self.cursor.execute("SELECT * FROM Settings")
settings = self.cursor.fetchone()
if settings[0] != DB_VERSION:
- logging.error("outdated or too new database version (%s) - please recreate tables"
+ log.error("outdated or too new database version (%s) - please recreate tables"
% (settings[0]))
self.wrongDbVersion = True
except:# _mysql_exceptions.ProgrammingError:
@@ -422,11 +423,6 @@ class Database:
log.info("failed to read settings table - recreating tables")
self.recreate_tables()
self.check_version(database=database, create=False)
- if not self.wrongDbVersion:
- msg = "Edit your screen_name and hand history path in the supported_sites "\
- +"section of the \nPreferences window (Main menu) before trying to import hands"
- print "\n%s" % msg
- log.warning(msg)
else:
print "Failed to read settings table - please recreate tables"
log.info("failed to read settings table - please recreate tables")
@@ -436,7 +432,27 @@ class Database:
#end def connect
def commit(self):
- self.connection.commit()
+ if self.backend != self.SQLITE:
+ self.connection.commit()
+ else:
+ # sqlite commits can fail because of shared locks on the database (SQLITE_BUSY)
+ # re-try commit if it fails in case this happened
+ maxtimes = 5
+ pause = 1
+ ok = False
+ for i in xrange(maxtimes):
+ try:
+ ret = self.connection.commit()
+ log.debug("commit finished ok, i = "+str(i))
+ ok = True
+ except:
+ log.debug("commit "+str(i)+" failed: info=" + str(sys.exc_info())
+ + " value=" + str(sys.exc_value))
+ sleep(pause)
+ if ok: break
+ if not ok:
+ log.debug("commit failed")
+ raise FpdbError('sqlite commit failed')
def rollback(self):
self.connection.rollback()
@@ -1311,7 +1327,6 @@ class Database:
c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('Partouche', 'EUR')")
- c.execute("INSERT INTO Sites (name,currency) VALUES ('Carbon', 'USD')")
if self.backend == self.SQLITE:
c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);")
elif self.backend == self.PGSQL:
@@ -1751,7 +1766,10 @@ class Database:
def insertPlayer(self, name, site_id):
result = None
- _name = Charset.to_db_utf8(name)
+ if self.backend == self.SQLITE:
+ _name = name
+ else:
+ _name = Charset.to_db_utf8(name)
c = self.get_cursor()
q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s"
q = q.replace('%s', self.sql.query['placeholder'])
@@ -1907,7 +1925,7 @@ class Database:
# end def send_finish_msg():
def tRecogniseTourneyType(self, tourney):
- logging.debug("Database.tRecogniseTourneyType")
+ log.debug("Database.tRecogniseTourneyType")
typeId = 1
# Check if Tourney exists, and if so retrieve TTypeId : in that case, check values of the ttype
cursor = self.get_cursor()
@@ -1923,10 +1941,10 @@ class Database:
try:
len(result)
typeId = result[0]
- logging.debug("Tourney found in db with Tourney_Type_ID = %d" % typeId)
+ log.debug("Tourney found in db with Tourney_Type_ID = %d" % typeId)
for ev in expectedValues :
if ( getattr( tourney, expectedValues.get(ev) ) <> result[ev] ):
- logging.debug("TypeId mismatch : wrong %s : Tourney=%s / db=%s" % (expectedValues.get(ev), getattr( tourney, expectedValues.get(ev)), result[ev]) )
+ log.debug("TypeId mismatch : wrong %s : Tourney=%s / db=%s" % (expectedValues.get(ev), getattr( tourney, expectedValues.get(ev)), result[ev]) )
typeIdMatch = False
#break
except:
@@ -1936,7 +1954,7 @@ class Database:
if typeIdMatch == False :
# Check for an existing TTypeId that matches tourney info (buyin/fee, knockout, rebuy, speed, matrix, shootout)
# if not found create it
- logging.debug("Searching for a TourneyTypeId matching TourneyType data")
+ log.debug("Searching for a TourneyTypeId matching TourneyType data")
cursor.execute (self.sql.query['getTourneyTypeId'].replace('%s', self.sql.query['placeholder']),
(tourney.siteId, tourney.buyin, tourney.fee, tourney.isKO,
tourney.isRebuy, tourney.speed, tourney.isHU, tourney.isShootout, tourney.isMatrix)
@@ -1946,9 +1964,9 @@ class Database:
try:
len(result)
typeId = result[0]
- logging.debug("Existing Tourney Type Id found : %d" % typeId)
+ log.debug("Existing Tourney Type Id found : %d" % typeId)
except TypeError: #this means we need to create a new entry
- logging.debug("Tourney Type Id not found : create one")
+ log.debug("Tourney Type Id not found : create one")
cursor.execute (self.sql.query['insertTourneyTypes'].replace('%s', self.sql.query['placeholder']),
(tourney.siteId, tourney.buyin, tourney.fee, tourney.isKO, tourney.isRebuy,
tourney.speed, tourney.isHU, tourney.isShootout, tourney.isMatrix)
diff --git a/pyfpdb/Exceptions.py b/pyfpdb/Exceptions.py
index fd7c20e3..789c7b83 100644
--- a/pyfpdb/Exceptions.py
+++ b/pyfpdb/Exceptions.py
@@ -48,5 +48,11 @@ class FpdbPostgresqlNoDatabase(FpdbDatabaseError):
def __str__(self):
return repr(self.value +" " + self.errmsg)
-class DuplicateError(FpdbError):
+class FpdbHandError(FpdbError):
+ pass
+
+class FpdbHandDuplicate(FpdbHandError):
+ pass
+
+class FpdbHandPartial(FpdbHandError):
pass
diff --git a/pyfpdb/GuiAutoImport.py b/pyfpdb/GuiAutoImport.py
index f9f1c335..628f7b7f 100755
--- a/pyfpdb/GuiAutoImport.py
+++ b/pyfpdb/GuiAutoImport.py
@@ -194,7 +194,7 @@ class GuiAutoImport (threading.Thread):
widget.set_label(u' _Stop Autoimport ')
if self.pipe_to_hud is None:
if os.name == 'nt':
- command = "python HUD_main.py " + self.settings['cl_options']
+ command = "python "+sys.path[0]+"\\HUD_main.py " + self.settings['cl_options']
bs = 0
else:
command = os.path.join(sys.path[0], 'HUD_main.py')
diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py
index 2a1829ae..df144e92 100755
--- a/pyfpdb/HUD_main.py
+++ b/pyfpdb/HUD_main.py
@@ -212,6 +212,7 @@ class HUD_main(object):
# get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed
+ log.info("HUD_main.read_stdin: hand processing starting ...")
try:
(table_name, max, poker_game, type, site_id, site_name, num_seats, tour_number, tab_number) = \
self.db_connection.get_table_info(new_hand_id)
@@ -237,6 +238,7 @@ class HUD_main(object):
try:
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days']
, self.hud_dict[temp_key].hud_params['h_hud_days'])
+ t4 = time.time()
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id])
self.hud_dict[temp_key].stat_dict = stat_dict
except KeyError: # HUD instance has been killed off, key is stale
@@ -245,6 +247,7 @@ class HUD_main(object):
# Unlocks table, copied from end of function
self.db_connection.connection.rollback()
return
+ t5 = time.time()
cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id)
if comm_cards != {}: # stud!
@@ -257,10 +260,8 @@ class HUD_main(object):
else:
# get stats using default params--also get cards
self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] )
- t4 = time.time()
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params
,self.hero_ids[site_id], num_seats)
- t5 = time.time()
cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id)
if comm_cards != {}: # stud!
diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py
index 93661d70..9c7ea23f 100644
--- a/pyfpdb/Hand.py
+++ b/pyfpdb/Hand.py
@@ -229,8 +229,7 @@ db: a connected Database object"""
# TourneysPlayers
else:
log.info("Hand.insert(): hid #: %s is a duplicate" % hh['siteHandNo'])
- #Raise Duplicate exception?
- pass
+ raise FpdbHandDuplicate(hh['siteHandNo'])
def updateHudCache(self, db):
db.storeHudCache(self.dbid_gt, self.dbid_pids, self.starttime, self.stats.getHandsPlayers())
@@ -636,7 +635,7 @@ class HoldemOmahaHand(Hand):
if builtFrom == "HHC":
hhc.readHandInfo(self)
if self.gametype['type'] == 'tour':
- self.tablename = "%s %s" % (self.tourNo, self.tablename)
+ self.tablename = "%s %s" % (self.tourNo, self.tablename)
hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(self)
hhc.markStreets(self)
@@ -932,7 +931,7 @@ class DrawHand(Hand):
if builtFrom == "HHC":
hhc.readHandInfo(self)
if self.gametype['type'] == 'tour':
- self.tablename = "%s %s" % (self.tourNo, self.tablename)
+ self.tablename = "%s %s" % (self.tourNo, self.tablename)
hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(self)
hhc.markStreets(self)
@@ -1128,7 +1127,7 @@ class StudHand(Hand):
if builtFrom == "HHC":
hhc.readHandInfo(self)
if self.gametype['type'] == 'tour':
- self.tablename = "%s %s" % (self.tourNo, self.tablename)
+ self.tablename = "%s %s" % (self.tourNo, self.tablename)
hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(self)
hhc.markStreets(self)
@@ -1220,7 +1219,7 @@ Add a complete on [street] by [player] to [amountTo]
# showdownPot INT, /* pot size at sd/street7 */
return (0,0,0,0,0)
-
+
def writeHand(self, fh=sys.__stdout__):
# PokerStars format.
@@ -1615,4 +1614,3 @@ ORDER BY
return h
-
diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py
index 5136d56b..f202698d 100755
--- a/pyfpdb/fpdb.py
+++ b/pyfpdb/fpdb.py
@@ -769,7 +769,7 @@ class fpdb:
self.status_bar.show()
if self.db is not None and self.db.connected:
- self.status_bar.set_text("Status: Connected to %s database named %s on host %s"
+ self.status_bar.set_text("Status: Connected to %s database named %s on host %s"
% (self.db.get_backend_name(),self.db.database, self.db.host))
# rollback to make sure any locks are cleared:
self.db.rollback()
@@ -902,8 +902,8 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.load_profile()
self.statusIcon = gtk.StatusIcon()
- if os.path.exists('../gfx/fpdb-cards.png'):
- self.statusIcon.set_from_file('../gfx/fpdb-cards.png')
+ if os.path.exists(os.path.join(sys.path[0], '../gfx/fpdb-cards.png')):
+ self.statusIcon.set_from_file(os.path.join(sys.path[0], '../gfx/fpdb-cards.png'))
elif os.path.exists('/usr/share/pixmaps/fpdb-cards.png'):
self.statusIcon.set_from_file('/usr/share/pixmaps/fpdb-cards.png')
else:
diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py
index fe66fcda..859a6bc0 100644
--- a/pyfpdb/fpdb_import.py
+++ b/pyfpdb/fpdb_import.py
@@ -365,7 +365,7 @@ class Importer:
pass
(stored, duplicates, partial, errors, ttime) = self.import_file_dict(self.database, file, self.filelist[file][0], self.filelist[file][1], None)
try:
- if not os.path.isdir(file):
+ if not os.path.isdir(file): # Note: This assumes that whatever calls us has an "addText" func
self.caller.addText(" %d stored, %d duplicates, %d partial, %d errors (time = %f)" % (stored, duplicates, partial, errors, ttime))
except KeyError: # TODO: Again, what error happens here? fix when we find out ..
pass
@@ -402,7 +402,7 @@ class Importer:
return (0,0,0,0,0)
conv = None
- (stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, 0)
+ (stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, time())
file = file.decode(Configuration.LOCALE_ENCODING)
@@ -437,12 +437,15 @@ class Importer:
for hand in handlist:
if hand is not None:
- #try, except duplicates here?
hand.prepInsert(self.database)
- hand.insert(self.database)
- if self.callHud and hand.dbid_hands != 0:
- to_hud.append(hand.dbid_hands)
- else:
+ try:
+ hand.insert(self.database)
+ except Exceptions.FpdbHandDuplicate:
+ duplicates += 1
+ else:
+ if self.callHud and hand.dbid_hands != 0:
+ to_hud.append(hand.dbid_hands)
+ else: # TODO: Treat empty as an error, or just ignore?
log.error("Hand processed but empty")
self.database.commit()
# Call hudcache update if not in bulk import mode
@@ -460,13 +463,16 @@ class Importer:
errors = getattr(hhc, 'numErrors')
stored = getattr(hhc, 'numHands')
+ stored -= duplicates
else:
# conversion didn't work
# TODO: appropriate response?
- return (0, 0, 0, 1, 0)
+ return (0, 0, 0, 1, time() - ttime)
else:
log.warning("Unknown filter filter_name:'%s' in filter:'%s'" %(filter_name, filter))
- return (0, 0, 0, 1, 0)
+ return (0, 0, 0, 1, time() - ttime)
+
+ ttime = time() - ttime
#This will barf if conv.getStatus != True
return (stored, duplicates, partial, errors, ttime)
diff --git a/run_fpdb.py b/run_fpdb.py
index 24f6a4dd..78e2803b 100755
--- a/run_fpdb.py
+++ b/run_fpdb.py
@@ -1,34 +1,34 @@
-#!/usr/bin/python
-
-#Copyright 2008 Carl Gherardi
-#This program is free software: you can redistribute it and/or modify
-#it under the terms of the GNU Affero General Public License as published by
-#the Free Software Foundation, version 3 of the License.
-#
-#This program is distributed in the hope that it will be useful,
-#but WITHOUT ANY WARRANTY; without even the implied warranty of
-#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-#GNU General Public License for more details.
-#
-#You should have received a copy of the GNU Affero General Public License
-#along with this program. If not, see .
-#In the "official" distribution you can find the license in
-#agpl-3.0.txt in the docs folder of the package.
-
-
-import os
-import sys
-
-# sys.path[0] holds the directory run_fpdb.py is in
-sys.path[0] = sys.path[0]+os.sep+"pyfpdb"
-os.chdir(sys.path[0])
-#print "sys.path[0] =", sys.path[0], "cwd =", os.getcwd()
-
-
-import fpdb
-
-
-if __name__ == "__main__":
- me = fpdb.fpdb()
- me.main()
- exit()
+#!/usr/bin/python
+
+#Copyright 2008 Carl Gherardi
+#This program is free software: you can redistribute it and/or modify
+#it under the terms of the GNU Affero General Public License as published by
+#the Free Software Foundation, version 3 of the License.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Affero General Public License
+#along with this program. If not, see .
+#In the "official" distribution you can find the license in
+#agpl-3.0.txt in the docs folder of the package.
+
+
+import os
+import sys
+
+# sys.path[0] holds the directory run_fpdb.py is in
+sys.path[0] = sys.path[0]+os.sep+"pyfpdb"
+os.chdir(sys.path[0])
+#print "sys.path[0] =", sys.path[0], "cwd =", os.getcwd()
+
+
+import fpdb
+
+
+if __name__ == "__main__":
+ me = fpdb.fpdb()
+ me.main()
+ exit()