Skip to content

Commit

Permalink
Created "madebidderids" command and removed from mod11codes. Added un…
Browse files Browse the repository at this point in the history
…ittests for this.
  • Loading branch information
chmarr committed Mar 18, 2013
1 parent 2c87c0a commit fe6e1f5
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 83 deletions.
45 changes: 45 additions & 0 deletions artshow/management/commands/makebidderids.py
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,45 @@
from optparse import make_option

from django.core.management.base import BaseCommand, CommandError

from artshow.mod11codes import make_check


class Command(BaseCommand):
args = "firstcode numcodes"
help = "Generate a list of valid BidderID codes"
option_list = BaseCommand.option_list + (
make_option("--digits", type="int", default=3, help="pad to this many digits [%default]"),
make_option("--allow-x", action="store_true", default=False, help="allow X checkdigit"),
make_option("--prefix", type="str", default="", help="prefix characters [%default]"),
make_option("--suffix", type="str", default="", help="suffix characters [%default]"),
make_option("--offset", type="int", default=0, help="offset checkdigit [%default]"),
)

def handle(self, *args, **options):
try:
first_code, num_codes = args
except ValueError:
raise CommandError("incorrect number of parameters")
try:
first_code = int(first_code)
except ValueError:
raise CommandError("firstcode is not an integer")
try:
num_codes = int(num_codes)
except ValueError:
raise CommandError("numcodes is not an integer")
value = first_code
digits = options['digits']
allow_x = options['allow_x']
prefix = options['prefix']
suffix = options['suffix']
offset = options['offset']
while num_codes > 0:
code = "%0*d" % (digits, value)
value += 1
check = make_check(code,offset=offset)
if check=="X" and not allow_x:
continue
print prefix + code + check + suffix
num_codes -= 1
95 changes: 12 additions & 83 deletions artshow/mod11codes.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -3,101 +3,30 @@
# Copyright (C) 2009, 2010 Chris Cogdon # Copyright (C) 2009, 2010 Chris Cogdon
# See file COPYING for licence details # See file COPYING for licence details


import optparse # The first element must be 1 for check-digit calculation to be correct
import sys

default_factors = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] default_factors = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]




class CheckDigitError(ValueError): class CheckDigitError(ValueError):
pass pass




def make_check(s, check10="X", factors=default_factors): def make_check(s, check10="X", factors=default_factors, offset=0):
tally = 0 tally = -offset
for i in range(len(s)): for i in range(len(s)):
tally += int(s[-1 - i]) * factors[(1 + i) % len(factors)] tally += int(s[-1 - i]) * factors[(1 + i) % len(factors)]
check = (-tally) % 11 check = (-tally) % 11
if check == 10: return str(check) if check != 10 else check10
return check10
else:
return str(check)




def check(s, check10="X", start=0, end=None, factors=default_factors): def check(s, check10="X", factors=default_factors, offset=0):
s2 = s[start:end] tally = -offset
tally = 0 for i in range(len(s)):
for i in range(len(s2)): c = s[-1 - i]
c = s2[-1 - i] try:
c = (c == check10) and 10 or int(c) c = int(c) if c != check10 else 10
except ValueError:
raise CheckDigitError("invalid character: %s" % c)
tally += c * factors[i % len(factors)] tally += c * factors[i % len(factors)]
if tally % 11 != 0: if tally % 11 != 0:
raise CheckDigitError("check digit failed for " + s) raise CheckDigitError("check digit failed for " + s)


def make_codes(num, first=0, count=1, min_digits=3, check10=False, factors=default_factors):
i = 0
bare_code = first
while i < num:
bare_code_str = "%0*d" % (min_digits, bare_code)
bare_code += 1
check = make_check(bare_code_str, factors=factors)
if check == "X":
if not check10:
continue
check = check10
for c in range(count):
yield bare_code_str + check
i += 1


def _get_options():
# noinspection PyUnusedLocal
def factors_callback(option, opt, value, parser):
try:
factors = value.split(",")
factors = [int(x) for x in factors]
parser.values.factors = factors
except ValueError, x:
raise optparse.OptionValueError(str(x))

parser = optparse.OptionParser()
parser.add_option("-c", "--count", type="int", default=1)
parser.add_option("--min_digits", type="int", default=3)
parser.add_option("--check10", type="str", default="")
parser.add_option("--prefix", type="str", default="")
parser.add_option("--suffix", type="str", default="")
parser.add_option("--factors", type="str", action="callback", callback=factors_callback, default=default_factors)
parser.add_option("--check", action="store_true", default=False)
opts, args = parser.parse_args()

if opts.check:
opts.sample = args[0]
else:
opts.num = int(args[0])
try:
opts.first = int(args[1])
except IndexError:
opts.first = 0

return opts


def _main():
opts = _get_options()
if opts.check:
try:
check(opts.sample, check10=opts.check10, start=len(opts.prefix), end=len(opts.suffix) or None,
factors=opts.factors)
except ValueError, x:
print >> sys.stderr, x
raise SystemExit(1)
else:
for c in make_codes(opts.num, opts.first, opts.count, min_digits=opts.min_digits, check10=opts.check10,
factors=opts.factors):
print opts.prefix + c + opts.suffix


if __name__ == "__main__":
_main()

21 changes: 21 additions & 0 deletions artshow/tests.py
Original file line number Original file line Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.test import TestCase from django.test import TestCase
from artshow.utils import artshow_settings from artshow.utils import artshow_settings
from django.conf import settings from django.conf import settings
from artshow import mod11codes




class AttributeFilterTest (TestCase): class AttributeFilterTest (TestCase):
Expand All @@ -15,3 +16,23 @@ def get_secret_key():
self.assertRaisesRegexp(AttributeError, self.assertRaisesRegexp(AttributeError,
"AttributeFilter blocked access to 'SECRET_KEY'.*", "AttributeFilter blocked access to 'SECRET_KEY'.*",
get_secret_key) get_secret_key)


class Mod11Test (TestCase):
def test_generation(self):
self.assertEqual(mod11codes.make_check("196"), "1")
self.assertEqual(mod11codes.make_check("197"), "X")
self.assertEqual(mod11codes.make_check("197", check10="@"), "@")
self.assertEqual(mod11codes.make_check("197", offset=4), "3")

def test_check_passes(self):
self.assertIsNone(mod11codes.check("1961"))
self.assertIsNone(mod11codes.check("197X"))
self.assertIsNone(mod11codes.check("197@", check10="@"))
self.assertIsNone(mod11codes.check("1973", offset=4))

def test_check_failures(self):
self.assertRaises(mod11codes.CheckDigitError, mod11codes.check, "196X")
self.assertRaises(mod11codes.CheckDigitError, mod11codes.check, "1970")
self.assertRaises(mod11codes.CheckDigitError, mod11codes.check, "197X", check10="@")
self.assertRaises(mod11codes.CheckDigitError, mod11codes.check, "197X", offset=4)

0 comments on commit fe6e1f5

Please sign in to comment.