python-stdnum commit: r1 - in python-stdnum: . stdnum stdnum/isbn
[Date Prev][
Date Next]
[Thread Prev][
Thread Next]
python-stdnum commit: r1 - in python-stdnum: . stdnum stdnum/isbn
- From: "Commits of the python-stdnum project." <python-stdnum-commits [at] lists.arthurdejong.org>
- To: python-stdnum-commits [at] lists.arthurdejong.org
- Reply-to: python-stdnum-users [at] lists.arthurdejong.org
- Subject: python-stdnum commit: r1 - in python-stdnum: . stdnum stdnum/isbn
- Date: Fri, 23 Jul 2010 15:40:34 +0200 (CEST)
Author: arthur
Date: Fri Jul 23 15:40:33 2010
New Revision: 1
URL: http://arthurdejong.org/viewvc/python-stdnum?view=rev&revision=1
Log:
make a initial repository layout with an implementation of the isbn module
Added:
python-stdnum/
python-stdnum/README
python-stdnum/stdnum/
python-stdnum/stdnum/__init__.py
python-stdnum/stdnum/isbn/
python-stdnum/stdnum/isbn/__init__.py
python-stdnum/stdnum/isbn/ranges.py
Added: python-stdnum/README
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ python-stdnum/README Fri Jul 23 15:40:33 2010 (r1)
@@ -0,0 +1,9 @@
+
+The goal of this project is to make a library to parse number formats and
+codes in different formats.
+
+Most notably this starts with ISBN and SSBN numbers.
+
+
+
+
Added: python-stdnum/stdnum/__init__.py
==============================================================================
Added: python-stdnum/stdnum/isbn/__init__.py
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ python-stdnum/stdnum/isbn/__init__.py Fri Jul 23 15:40:33 2010
(r1)
@@ -0,0 +1,145 @@
+# __init__.py - functions for handling ISBNs
+#
+# Copyright (C) 2010 Arthur de Jong
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+"""Module for handling ISBNs. This module handles both numbers in ISBN10
+(10-digit) and ISB13 (13-digit) format.
+
+>>> validate('978-9024538270')
+True
+>>> validate('978-9024538271') # incorrect check digit
+False
+>>> compact('1-85798-218-5')
+'1857982185'
+>>> format('9780471117094')
+'978-0-471-11709-4'
+>>> isbn_type('1-85798-218-5')
+'ISBN10'
+>>> isbn_type('978-0-471-11709-4')
+'ISBN13'
+>>> to_isbn13('1-85798-218-5')
+'978-1-85798-218-X') ******************************************
+"""
+
+
+def compact(number):
+ """Convert the ISBN to the minimal representation. This strips the number
+ of any valid ISBN separators and removes surrounding whitespace."""
+ number = number.replace(' ','').replace('-','').strip().upper()
+ if len(number) == 9:
+ number = '0' + number
+ return number
+
+def _calc_isbn10_check_digit(number):
+ """Calculate the ISBN check digit for 10-digit numbers. The number passed
+ should not have the check bit included."""
+ check = sum( (i + 1) * int(number[i]) for i in range(len(number)) ) % 11
+ return 'X' if check == 10 else str(check)
+
+def _calc_isbn13_check_digit(number):
+ """Calculate the ISBN check digit for 13-digit numbers. The number passed
+ should not have the check bit included."""
+ return str((10 - sum( (2 * (i % 2) + 1) * int(number[i]) for i in
range(len(number)))) % 10)
+
+def isbn_type(number):
+ """Check the passed number and returns 'ISBN13', 'ISBN10' or None (for
+ invalid) for checking the type of number passed."""
+ number = compact(number)
+ if len(number) == 10:
+ if not number[:-1].isdigit():
+ #raise ValueError('ISBN should be numeric')
+ return None
+ if _calc_isbn10_check_digit(number[:-1]) != number[-1]:
+ #raise ValueError('ISBN check digit incorrect')
+ return None
+ return 'ISBN10'
+ elif len(number) == 13:
+ if not number.isdigit():
+ #raise ValueError('ISBN should be numeric')
+ return None
+ if _calc_isbn13_check_digit(number[:-1]) != number[-1]:
+ #raise ValueError('ISBN check digit incorrect')
+ return None
+ return 'ISBN13'
+ else:
+ #raise ValueError('ISBN has invalid length')
+ return None
+
+
+ '''
+ try:
+ number = compact(number)
+ except ValueError:
+ return None
+ if len(number) == 10:
+ return 'ISBN10'
+ else:
+ return 'ISBN13'
+ '''
+
+def validate(number):
+ """Checks to see if the number provided is a valid ISBN (either a legacy
+ 10-digit one or a 13-digit one). This checks the length and the check
+ bit but does not check if the group and publisher are valid (use split()
+ for that)."""
+ return isbn_type(number) is not None
+
+def to_isbn13(number):
+ """Convert the number to ISBN13 format."""
+ number = number.strip()
+ min_number = compact(number)
+ if len(min_number) == 13:
+ return number # nothing to do, already ISBN13
+ # put new check digit in place
+ number = number[:-1] + _calc_isbn13_check_digit('978' + min_number)
+ # add prefix
+ if ' ' in number:
+ return '978 ' + number
+ elif '-' in number:
+ return '978-' + number
+ else:
+ return '978' + number
+
+def split(number):
+ """Split the specified ISBN into an EAN.UCC prefix, a group prefix, a
+ registrant, an item number and a check-digit. If the number is in ISNB10
+ format the returned EAN.UCC prefix is '978'."""
+ import ranges
+ # clean up number
+ number = compact(number)
+ # get Bookland prefix if any
+ if len(number) == 10:
+ oprefix = ''
+ prefix = '978'
+ else:
+ oprefix = prefix = number[:3]
+ number = number[3:]
+ # get group
+ group, number = ranges.lookup(prefix, number)
+ publisher, number = ranges.lookup('%s-%s' % (prefix, group), number)
+ itemnr = number[:-1]
+ check = number[-1]
+ return ( oprefix, group, publisher, itemnr, check )
+
+def format(number, separator='-'):
+ """Reformat the passed number to the standard format with the EAN.UCC
+ prefix (if any), the group prefix, the registrant, the item number and
+ the check-digit separated (if possible) by the specified separator.
+ Passing an empty separator should equal compact() though this is less
+ efficient."""
+ return separator.join(x for x in split(number) if x)
Added: python-stdnum/stdnum/isbn/ranges.py
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ python-stdnum/stdnum/isbn/ranges.py Fri Jul 23 15:40:33 2010 (r1)
@@ -0,0 +1,390 @@
+# ranges.py - list of ISBN prefix data and utility functions
+#
+# Copyright (C) 2010 Arthur de Jong
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+"""This module contains that current ISBN group and registrant prefixes as
+they are registered with the International ISBN Agency. This information
+is needed to correctly split an ISBN into an EAN.UCC prefix, a group prefix,
+a registrant, an item number and a check-digit."""
+
+# The place where the current version of RangeMessage.xml can be downloaded.
+_download_url = 'http://www.isbn-international.org/agency?rmxml=1'
+
+# What follows is a representation of the prefixes that are defined by
+# International ISBN Agency to correctly split ISBNs. See the download()
+# and output() methods on how to download and generate this data.
+
+# generated from RangeMessage.xml, downloaded from
+# http://www.isbn-international.org/agency?rmxml=1
+# serial 0aad2b046ddd9b30e080cb2b24afc868
+# date Thu, 20 May 2010 18:36:55 GMT
+_prefixes = """
+978 0-5 600-649 7-7 80-94 950-989 9900-9989 99900-99999
+978-0 00-19 200-699 7000-8499 85000-89999 900000-949999 9500000-9999999
+978-1 00-09 100-399 4000-5499 55000-86979 869800-998999 9990000-9999999
+978-2 00-19 200-349 35000-39999 400-699 7000-8399 84000-89999 900000-949999
+978-2 9500000-9999999
+978-3 00-02 030-033 0340-0369 03700-03999 04-19 200-699 7000-8499 85000-89999
+978-3 900000-949999 9500000-9539999 95400-96999 9700000-9899999 99000-99499
+978-3 99500-99999
+978-4 00-19 200-699 7000-8499 85000-89999 900000-949999 9500000-9999999
+978-5 00-19 200-420 4210-4299 430-430 4310-4399 440-440 4410-4499 450-699
+978-5 7000-8499 85000-89999 900000-909999 91000-91999 9200-9299 93000-94999
+978-5 9500000-9500999 9501-9799 98000-98999 9900000-9909999 9910-9999
+978-600 00-09 100-499 5000-8999 90000-99999
+978-601 00-19 200-699 7000-7999 80000-84999 85-99
+978-602 00-19 200-799 8000-9499 95000-99999
+978-603 00-04 05-49 500-799 8000-8999 90000-99999
+978-604 0-4 50-89 900-979 9800-9999
+978-605 01-09 100-399 4000-5999 60000-89999 90-99
+978-606 0-0 10-49 500-799 8000-9199 92000-99999
+978-607 00-39 400-749 7500-9499 95000-99999
+978-608 0-0 10-19 200-449 4500-6499 65000-69999 7-9
+978-609 00-39 400-799 8000-9499 95000-99999
+978-612 00-29 300-399 4000-4499 45000-49999 50-99
+978-613 0-9
+978-614 00-39 400-799 8000-9499 95000-99999
+978-615 00-09 100-499 5000-7999 80000-89999
+978-616 00-19 200-699 7000-8999 90000-99999
+978-617 00-49 500-699 7000-8999 90000-99999
+978-7 00-09 100-499 5000-7999 80000-89999 900000-999999
+978-80 00-19 200-699 7000-8499 85000-89999 900000-999999
+978-81 00-19 200-699 7000-8499 85000-89999 900000-999999
+978-82 00-19 200-699 7000-8999 90000-98999 990000-999999
+978-83 00-19 200-599 60000-69999 7000-8499 85000-89999 900000-999999
+978-84 00-14 15000-19999 200-699 7000-8499 85000-89999 9000-9199
+978-84 920000-923999 92400-92999 930000-949999 95000-96999 9700-9999
+978-85 00-19 200-599 60000-69999 7000-8499 85000-89999 900000-979999
+978-85 98000-99999
+978-86 00-29 300-599 6000-7999 80000-89999 900000-999999
+978-87 00-29 400-649 7000-7999 85000-94999 970000-999999
+978-88 00-19 200-599 6000-8499 85000-89999 900000-949999 95000-99999
+978-89 00-24 250-549 5500-8499 85000-94999 950000-999999
+978-90 00-19 200-499 5000-6999 70000-79999 800000-849999 8500-8999 90-90
+978-90 910000-939999 94-94 950000-999999
+978-91 0-1 20-49 500-649 7000-7999 85000-94999 970000-999999
+978-92 0-5 60-79 800-899 9000-9499 95000-98999 990000-999999
+978-93 00-09 100-499 5000-7999 80000-94999 950000-999999
+978-94 000-599 6000-8999 90000-99999
+978-950 00-49 500-899 9000-9899 99000-99999
+978-951 0-1 20-54 550-889 8900-9499 95000-99999
+978-952 00-19 200-499 5000-5999 60-65 6600-6699 67000-69999 7000-7999 80-94
+978-952 9500-9899 99000-99999
+978-953 0-0 10-14 150-549 55000-59999 6000-9499 95000-99999
+978-954 00-28 2900-2999 300-799 8000-8999 90000-92999 9300-9999
+978-955 0000-1999 20-49 50000-54999 550-799 8000-9499 95000-99999
+978-956 00-19 200-699 7000-9999
+978-957 00-02 0300-0499 05-19 2000-2099 21-27 28000-30999 31-43 440-819
+978-957 8200-9699 97000-99999
+978-958 00-56 57000-59999 600-799 8000-9499 95000-99999
+978-959 00-19 200-699 7000-8499 85000-99999
+978-960 00-19 200-659 6600-6899 690-699 7000-8499 85000-92999 93-93 9400-9799
+978-960 98000-99999
+978-961 00-19 200-599 6000-8999 90000-94999
+978-962 00-19 200-699 7000-8499 85000-86999 8700-8999 900-999
+978-963 00-19 200-699 7000-8499 85000-89999 9000-9999
+978-964 00-14 150-249 2500-2999 300-549 5500-8999 90000-96999 970-989
+978-964 9900-9999
+978-965 00-19 200-599 7000-7999 90000-99999
+978-966 00-14 1500-1699 170-199 2000-2999 300-699 7000-8999 90000-99999
+978-967 00-29 300-499 5000-5999 60-89 900-989 9900-9989 99900-99999
+978-968 01-39 400-499 5000-7999 800-899 9000-9999
+978-969 0-1 20-39 400-799 8000-9999
+978-970 01-59 600-899 9000-9099 91000-96999 9700-9999
+978-971 000-015 0160-0199 02-02 0300-0599 06-09 10-49 500-849 8500-9099
+978-971 91000-98999 9900-9999
+978-972 0-1 20-54 550-799 8000-9499 95000-99999
+978-973 0-0 100-169 1700-1999 20-54 550-759 7600-8499 85000-88999 8900-9499
+978-973 95000-99999
+978-974 00-19 200-699 7000-8499 85000-89999 90000-94999 9500-9999
+978-975 00000-00999 01-01 02-24 250-599 6000-9199 92000-98999 990-999
+978-976 0-3 40-59 600-799 8000-9499 95000-99999
+978-977 00-19 200-499 5000-6999 700-999
+978-978 000-199 2000-2999 30000-79999 8000-8999 900-999
+978-979 000-099 1000-1499 15000-19999 20-29 3000-3999 400-799 8000-9499
+978-979 95000-99999
+978-980 00-19 200-599 6000-9999
+978-981 00-11 1200-1999 200-289 2900-9999
+978-982 00-09 100-699 70-89 9000-9799 98000-99999
+978-983 00-01 020-199 2000-3999 40000-44999 45-49 50-79 800-899 9000-9899
+978-983 99000-99999
+978-984 00-39 400-799 8000-8999 90000-99999
+978-985 00-39 400-599 6000-8999 90000-99999
+978-986 00-11 120-559 5600-7999 80000-99999
+978-987 00-09 1000-1999 20000-29999 30-49 500-899 9000-9499 95000-99999
+978-988 00-16 17000-19999 200-799 8000-9699 97000-99999
+978-989 0-1 20-54 550-799 8000-9499 95000-99999
+978-9927 00-09 100-399 4000-4999
+978-9928 00-09 100-399 4000-4999
+978-9929 0-3 40-54 550-799 8000-9999
+978-9930 00-49 500-939 9400-9999
+978-9931 00-29 300-899 9000-9999
+978-9932 00-39 400-849 8500-9999
+978-9933 0-0 10-39 400-899 9000-9999
+978-9934 0-0 10-49 500-799 8000-9999
+978-9935 0-0 10-39 400-899 9000-9999
+978-9936 0-1 20-39 400-799 8000-9999
+978-9937 0-2 30-49 500-799 8000-9999
+978-9938 00-79 800-949 9500-9999
+978-9939 0-4 50-79 800-899 9000-9999
+978-9940 0-1 20-49 500-899 9000-9999
+978-9941 0-0 10-39 400-899 9000-9999
+978-9942 00-89 900-994 9950-9999
+978-9943 00-29 300-399 4000-9999
+978-9944 0000-0999 100-499 5000-5999 60-69 700-799 80-89 900-999
+978-9945 00-00 010-079 08-39 400-569 57-57 580-849 8500-9999
+978-9946 0-1 20-39 400-899 9000-9999
+978-9947 0-1 20-79 800-999
+978-9948 00-39 400-849 8500-9999
+978-9949 0-0 10-39 400-899 9000-9999
+978-9950 00-29 300-849 8500-9999
+978-9951 00-39 400-849 8500-9999
+978-9952 0-1 20-39 400-799 8000-9999
+978-9953 0-0 10-39 400-599 60-89 9000-9999
+978-9954 0-1 20-39 400-799 8000-9999
+978-9955 00-39 400-929 9300-9999
+978-9956 0-0 10-39 400-899 9000-9999
+978-9957 00-39 400-699 70-84 8500-8799 88-99
+978-9958 0-0 10-49 500-899 9000-9999
+978-9959 0-1 20-79 800-949 9500-9999
+978-9960 00-59 600-899 9000-9999
+978-9961 0-2 30-69 700-949 9500-9999
+978-9962 00-54 5500-5599 56-59 600-849 8500-9999
+978-9963 0-2 30-54 550-734 7350-7499 7500-9999
+978-9964 0-6 70-94 950-999
+978-9965 00-39 400-899 9000-9999
+978-9966 000-199 20-69 7000-7499 750-959 9600-9999
+978-9967 00-39 400-899 9000-9999
+978-9968 00-49 500-939 9400-9999
+978-9970 00-39 400-899 9000-9999
+978-9971 0-5 60-89 900-989 9900-9999
+978-9972 00-09 1-1 200-249 2500-2999 30-59 600-899 9000-9999
+978-9973 00-05 060-089 0900-0999 10-69 700-969 9700-9999
+978-9974 0-2 30-54 550-749 7500-9499 95-99
+978-9975 0-0 100-399 4000-4499 45-89 900-949 9500-9999
+978-9976 0-5 60-89 900-989 9900-9999
+978-9977 00-89 900-989 9900-9999
+978-9978 00-29 300-399 40-94 950-989 9900-9999
+978-9979 0-4 50-64 650-659 66-75 760-899 9000-9999
+978-9980 0-3 40-89 900-989 9900-9999
+978-9981 00-09 100-159 1600-1999 20-79 800-949 9500-9999
+978-9982 00-79 800-989 9900-9999
+978-9983 80-94 950-989 9900-9999
+978-9984 00-49 500-899 9000-9999
+978-9985 0-4 50-79 800-899 9000-9999
+978-9986 00-39 400-899 9000-9399 940-969 97-99
+978-9987 00-39 400-879 8800-9999
+978-9988 0-2 30-54 550-749 7500-9999
+978-9989 0-0 100-199 2000-2999 30-59 600-949 9500-9999
+978-99901 00-49 500-799 80-99
+978-99903 0-1 20-89 900-999
+978-99904 0-5 60-89 900-999
+978-99905 0-3 40-79 800-999
+978-99906 0-2 30-59 600-699 70-89 90-94 950-999
+978-99908 0-0 10-89 900-999
+978-99909 0-3 40-94 950-999
+978-99910 0-2 30-89 900-999
+978-99911 00-59 600-999
+978-99912 0-3 400-599 60-89 900-999
+978-99913 0-2 30-35 600-604
+978-99914 0-4 50-89 900-999
+978-99915 0-4 50-79 800-999
+978-99916 0-2 30-69 700-999
+978-99917 0-2 30-89 900-999
+978-99918 0-3 40-79 800-999
+978-99919 0-2 300-399 40-69 900-999
+978-99920 0-4 50-89 900-999
+978-99921 0-1 20-69 700-799 8-8 90-99
+978-99922 0-3 40-69 700-999
+978-99923 0-1 20-79 800-999
+978-99924 0-1 20-79 800-999
+978-99925 0-3 40-79 800-999
+978-99926 0-0 10-59 600-999
+978-99927 0-2 30-59 600-999
+978-99928 0-0 10-79 800-999
+978-99929 0-4 50-79 800-999
+978-99930 0-4 50-79 800-999
+978-99931 0-4 50-79 800-999
+978-99932 0-0 10-59 600-699 7-7 80-99
+978-99933 0-2 30-59 600-999
+978-99934 0-1 20-79 800-999
+978-99935 0-2 30-59 600-699 7-8 90-99
+978-99936 0-0 10-59 600-999
+978-99937 0-1 20-59 600-999
+978-99938 0-1 20-59 600-899 90-99
+978-99939 0-5 60-89 900-999
+978-99940 0-0 10-69 700-999
+978-99941 0-2 30-79 800-999
+978-99942 0-4 50-79 800-999
+978-99943 0-2 30-59 600-999
+978-99944 0-4 50-79 800-999
+978-99945 0-5 60-89 900-999
+978-99946 0-2 30-59 600-999
+978-99947 0-2 30-69 700-999
+978-99948 0-4 50-79 800-999
+978-99949 0-1 20-89 900-999
+978-99950 0-4 50-79 800-999
+978-99952 0-4 50-79 800-999
+978-99953 0-2 30-79 800-939 94-99
+978-99954 0-2 30-69 700-999
+978-99955 0-1 20-59 600-799 80-89 90-99
+978-99956 00-59 600-859 86-99
+978-99957 0-1 20-79 800-999
+978-99958 0-4 50-94 950-999
+978-99959 0-2 30-59 600-999
+978-99960 0-0 10-94 950-999
+978-99961 0-3 40-89 900-999
+978-99962 0-4 50-79 800-999
+978-99963 00-49 500-999
+978-99964 0-1 20-79 800-999
+978-99965 0-3 40-79 800-999
+978-99966 0-2 30-69 700-799
+978-99967 0-1 20-59 600-899
+979 10-10
+979-10 00-19 200-699 7000-8999 90000-97599 976000-999999
+"""
+
+def _expand():
+ """Ensures that the prefix list is expanded as a dictionary to allow
+ easy lookups. The default text form is compact but not very efficient."""
+ global _prefixes
+ if type(_prefixes) == dict:
+ return
+ # build a new dictionary of ranges from the string
+ new_prefixes = dict()
+ for line in _prefixes.splitlines():
+ if line:
+ ( prefix, r ) = line.split(' ', 1)
+ range_list = new_prefixes.setdefault(prefix, [])
+ for r in r.split(' '):
+ low, high = r.split('-')
+ range_list.append((len(low), low, high))
+ # save the dictionary
+ _prefixes = new_prefixes
+
+def lookup(prefix, number):
+ """Look up the specified prefix and split the provided number split in
+ the correct parts. If the prefix cannot be found or the number is not
+ in any of the defined ranges a tuple with one element is returned.
+ The prefix and number together are expected to form a complete ISBN13
+ number.
+
+ >>> lookup('978', '9024538270')
+ ('90', '24538270')
+ >>> lookup('978-0', '471117094')
+ ('471', '117094')
+ """
+ _expand()
+ try:
+ for length, low, high in _prefixes[prefix]:
+ if low <= number[:length] <= high:
+ return number[:length], number[length:]
+ except KeyError:
+ pass
+ return ( number, )
+
+def load(fp):
+ """Loads the data from the specified file descriptor. The provided file
+ should match the format of the RangeMessage.xml file."""
+ # this is inline to avoid importing xml.sax for normal use
+ import xml.sax
+ # initialise data
+ global _prefixes
+ _prefixes = dict()
+ # SAX handler class
+ class RangeHandler(xml.sax.ContentHandler):
+ def __init__(self):
+ self._gather = None
+ self._prefix = None
+ self._range = None
+ self._length = None
+ def startElement(self, name, attrs):
+ if name in ( 'MessageSerialNumber', 'MessageDate', 'Prefix',
+ 'Range', 'Length', ):
+ self._gather = ''
+ def characters(self, content):
+ if self._gather is not None:
+ self._gather += content
+ def endElement(self, name):
+ if name == 'MessageSerialNumber':
+ global _download_serial
+ _download_serial = self._gather.strip()
+ elif name == 'MessageDate':
+ global _download_date
+ _download_date = self._gather.strip()
+ elif name == 'Prefix':
+ self._prefix = self._gather.strip()
+ elif name == 'Range':
+ self._range = self._gather.strip()
+ elif name == 'Length':
+ self._length = int(self._gather.strip())
+ elif name == 'Rule' and self._length:
+ r = ( self._length, ) + tuple( x[:self._length] for x in
self._range.split('-') )
+ _prefixes.setdefault(self._prefix, []).append(r)
+ self._gather = None
+ # start the actual parsing
+ parser = xml.sax.make_parser()
+ parser.setContentHandler(RangeHandler())
+ parser.parse(fp)
+
+def download(url=None):
+ """Download the RangeMessage.xml data from the International ISBN Agency
+ website or from the specified URL."""
+ import urllib
+ load(urllib.urlopen(url or _download_url))
+
+def _wrap(text, max_len, sep=' '):
+ """Generator that returns lines of text that are no longer than
+ max_len. The sep arguments is the string to split on."""
+ while text:
+ i = len(text)
+ if i > max_len:
+ i = text.rindex(' ', 20, max_len)
+ yield text[:i]
+ text = text[i+1:]
+
+def output(fp=None):
+ """Print the downloaded range data to stdout (or a file if one is
+ provided) in the compact text format suitable for inclusion in this
+ module."""
+ _expand()
+ if not fp:
+ import sys
+ fp = sys.stdout
+ # first print the header if we can
+ try:
+ fp.write('# generated from RangeMessage.xml, downloaded from\n'
+ '# %(url)s\n'
+ '# serial %(serial)s\n'
+ '# date %(date)s\n'
+ '_prefixes = """\n' % { 'url': _download_url,
+ 'serial': _download_serial,
+ 'date': _download_date })
+ headerprinted = True
+ except NameError:
+ headerprinted = False
+ # print the actual prefixes
+ prefixes = _prefixes.keys()
+ prefixes.sort()
+ for prefix in prefixes:
+ ranges = _prefixes[prefix]
+ for line in _wrap(' '.join(r[1] + '-' + r[2] for r in ranges), 77 -
len(prefix)):
+ fp.write('%s %s\n' % ( prefix, line ) )
+ # print the footer if the header was printed
+ if headerprinted:
+ fp.write('"""\n')
--
To unsubscribe send an email to
python-stdnum-commits-unsubscribe@lists.arthurdejong.org or see
http://lists.arthurdejong.org/python-stdnum-commits
- python-stdnum commit: r1 - in python-stdnum: . stdnum stdnum/isbn,
Commits of the python-stdnum project.