rfc: a self-editing script

1 view
Skip to first unread message

gb345

unread,
Oct 9, 2009, 7:30:16 PM10/9/09
to

The following fragment is from a tiny maintenance script that,
among other things, edits itself, by rewriting the line that ends
with '### REPLACE'.

######################################################################

import re
import fileinput

LAST_VERSION = 'VERSION 155' ### REPLACE

service = Service(url='http://url.to.service')

if service.version_string == LAST_VERSION:
sys.exit(0)

for line in fileinput.input(sys.argv[0], inplace=True):
if re.search(r"### REPLACE$", line):
print ("LAST_VERSION = '%s' ### REPLACE" %
service.version_string)
else:
print line,

# ...and goes on to do more stuff...

######################################################################

This script is meant to run periodically (via cron), and "do more
stuff" whenever the fetched value of service.version_string differs
from what it was at the time of the script's prior invocation.
(The interval of time between such changes of value varies from
one change to the next, but it is always of the order of several
weeks.)

Hence this script needs to preserve state between invocations.
The rationale for the acrobatics with fileinput above is to make
this script completely self-contained, by circumventing the need
some external means (e.g. a second file, or a DB) of preserving
state between invocations.

Is there a better way to circumvent the requirement for an external
repository of state information?

G

Steven D'Aprano

unread,
Oct 10, 2009, 3:58:58 AM10/10/09
to

Yes -- change the requirement. What's wrong with having a separate file
to store state?

Self-modifying code is almost always the wrong solution, unless the
problem is "how do I generate an unmaintainable mess?".

But if you absolutely have to write to the program file, then append your
data to the end of the file (as a comment) and later read that, rather
than modifying the actual code in place. That is, you fetch the
LAST_VERSION by reading the last non-empty line in the file, something
like this:


# Untested
def get_last_version(filename):
"""Retrieves the last version number from the given filename,
taken from the last non-empty line."""
candidate = ''
for line in open(filename, 'r'):
line = line.strip()
if line and line.startswith('#'):
candidate = line.lstrip('# \t')
# error checking goes here
return candidate

LAST_VERSION = get_last_version(sys.argv[0])

...
more code goes here
...


# ==================================================
# === Version number history goes here. ===
# === DO NOT insert any code after this point!!! ===
# ==================================================
# 1.0.1
# 1.0.2a
# 1.0.2
# 1.0.5


This has the added advantage that you can track the updates made to the
version number.

--
Steven

garabik-ne...@kassiopeia.juls.savba.sk

unread,
Oct 10, 2009, 6:18:53 AM10/10/09
to
Steven D'Aprano <st...@remove-this-cybersource.com.au> wrote:
...
> But if you absolutely have to write to the program file, then append your
> data to the end of the file (as a comment) and later read that, rather
> than modifying the actual code in place. That is, you fetch the
> LAST_VERSION by reading the last non-empty line in the file, something
> like this:

...

> # ==================================================
> # === Version number history goes here. ===
> # === DO NOT insert any code after this point!!! ===
> # ==================================================
> # 1.0.1
> # 1.0.2a
> # 1.0.2
> # 1.0.5
>
>
> This has the added advantage that you can track the updates made to the
> version number.
>

And my experience taught me that is pays off to include also date (and
time) of each change, preferably in the RFC 3339 format. Priceless when
you hunt for an unnoticed bug or a crash that happened sometime in the
past...

e.g.:

# 1.0.1 2006-08-07 12:34:56-06:00
# 1.0.2a 2006-08-08 13:35:57-07:00
# 1.0.2 2006-08-10 01:04:56-06:00

etc...

--
-----------------------------------------------------------
| Radovan Garabík http://kassiopeia.juls.savba.sk/~garabik/ |
| __..--^^^--..__ garabik @ kassiopeia.juls.savba.sk |
-----------------------------------------------------------
Antivirus alert: file .signature infected by signature virus.
Hi! I'm a signature virus! Copy me into your signature file to help me spread!

gb345

unread,
Oct 10, 2009, 4:04:40 PM10/10/09
to
In <0059c2b1$0$26930$c3e...@news.astraweb.com> Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> writes:

>But if you absolutely have to write to the program file...

No, don't have to, beyond the urge to satisfy a very idiosyncratic
aesthetic imperative...


Thanks, these are great ideas. Just the feedback I was looking for.

G.

Reply all
Reply to author
Forward
0 new messages