python-stdnum branch master updated. 1.7-23-g442aa82
[Date Prev][
Date Next]
[Thread Prev][
Thread Next]
python-stdnum branch master updated. 1.7-23-g442aa82
- 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 branch master updated. 1.7-23-g442aa82
- Date: Mon, 1 Jan 2018 10:16:09 +0100 (CET)
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-stdnum".
The branch, master has been updated
via 442aa8235b6621fbc79c7402e4da6231e3c7b4c6 (commit)
from 8a34b4e119ed40f8cd0e66f1e75d915290ccdfb5 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://arthurdejong.org/git/python-stdnum/commit/?id=442aa8235b6621fbc79c7402e4da6231e3c7b4c6
commit 442aa8235b6621fbc79c7402e4da6231e3c7b4c6
Author: srikanthlogic <srik.lak@gmail.com>
Date: Fri Dec 1 19:39:54 2017 +0530
Add Indian PAN
Closes https://github.com/arthurdejong/python-stdnum/pull/57
diff --git a/stdnum/in_/pan.py b/stdnum/in_/pan.py
new file mode 100644
index 0000000..6679b21
--- /dev/null
+++ b/stdnum/in_/pan.py
@@ -0,0 +1,120 @@
+# pan.py - functions for handling Indian Permanent Account number (PAN)
+#
+# Copyright (C) 2017 Srikanth Lakshmanan
+#
+# 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
+
+"""PAN (Permanent Account Number, Indian income tax identifier).
+
+The Permanent Account Number (PAN) is a 10 digit alphanumeric identifier for
+Indian individuals, families and corporates for income tax purposes.
+
+The number is built up of 5 characters, 4 numbers and 1 character. The fourth
+character indicates the type of holder of the number and the last character
+is computed by an undocumented checksum algorithm.
+
+More information:
+
+* https://en.wikipedia.org/wiki/Permanent_account_number
+
+>>> validate('ACUPA7085R')
+'ACUPA7085R'
+>>> validate('234123412347')
+Traceback (most recent call last):
+ ...
+InvalidLength: ...
+>>> validate('ABMPA32111') # check digit should be a letter
+Traceback (most recent call last):
+ ...
+InvalidFormat: ...
+>>> validate('ABMXA3211G') # invalid type of holder
+Traceback (most recent call last):
+ ...
+InvalidComponent: ...
+>>> mask('AAPPV8261K')
+'AAPPVXXXXK'
+>>> info('AAPPV8261K')['card_holder_type']
+'Individual'
+"""
+
+import re
+
+from stdnum.exceptions import *
+from stdnum.util import clean
+
+
+_pan_re = re.compile(r'^[A-Z]{3}[ABCFGHLJPTK][A-Z]\d{4}[A-Z]$')
+
+
+def compact(number):
+ """Convert the number to the minimal representation. This strips the
+ number of any valid separators and removes surrounding whitespace."""
+ return clean(number, ' -').upper().strip()
+
+
+def validate(number):
+ """Check if the number provided is a valid PAN. This checks the
+ length and formatting."""
+ number = compact(number)
+ if len(number) != 10:
+ raise InvalidLength()
+ if not (number[:5].isalpha() and number[5:-1].isdigit() and
+ number[-1].isalpha()):
+ raise InvalidFormat()
+ info(number) # used to check 4th digit
+ return number
+
+
+def is_valid(number):
+ """Check if the number provided is a valid PAN. This checks the
+ length and formatting."""
+ try:
+ return bool(validate(number))
+ except ValidationError:
+ return False
+
+
+_card_holder_types = {
+ 'A': 'Association of Persons (AOP)',
+ 'B': 'Body of Individuals (BOI)',
+ 'C': 'Company',
+ 'F': 'Firm',
+ 'G': 'Government',
+ 'H': 'HUF (Hindu Undivided Family)',
+ 'L': 'Local Authority',
+ 'J': 'Artificial Juridical Person',
+ 'P': 'Individual',
+ 'T': 'Trust (AOP)',
+ 'K': 'Krish (Trust Krish)',
+}
+
+
+def info(number):
+ """Provide information that can be decoded from the PAN."""
+ number = compact(number)
+ card_holder_type = _card_holder_types.get(number[3])
+ if not card_holder_type:
+ raise InvalidComponent()
+ return {
+ 'card_holder_type': card_holder_type,
+ 'initial': number[4],
+ }
+
+
+def mask(number):
+ """Mask the PAN as per CBDT masking standard."""
+ number = compact(number)
+ return number[:5] + 'XXXX' + number[-1:]
diff --git a/tests/test_in_pan.doctest b/tests/test_in_pan.doctest
new file mode 100644
index 0000000..e3179ee
--- /dev/null
+++ b/tests/test_in_pan.doctest
@@ -0,0 +1,40 @@
+test_in_pan.doctest - more detailed doctests for stdnum.in_.pan module
+
+Copyright (C) 2017 Srikanth Lakshmanan
+
+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 file contains more detailed doctests for the stdnum.in_.pan module. It
+tries to cover more corner cases and detailed functionality that is not
+really useful as module documentation.
+
+>>> from stdnum.in_ import pan
+>>> from stdnum.exceptions import *
+
+These number have been provided and should all be valid PANs.
+
+>>> numbers = '''
+...
+... AAKFD7113K
+... AAPPV8261K
+... ABMPA3211G
+... ACUPA7085R
+... AFZPK7190K
+...
+... '''
+>>> [x for x in numbers.splitlines() if x and not pan.is_valid(x)]
+[]
-----------------------------------------------------------------------
Summary of changes:
stdnum/in_/pan.py | 120 +++++++++++++++++++++
tests/{test_ch_ssn.doctest => test_in_pan.doctest} | 31 +++---
2 files changed, 139 insertions(+), 12 deletions(-)
create mode 100644 stdnum/in_/pan.py
copy tests/{test_ch_ssn.doctest => test_in_pan.doctest} (62%)
hooks/post-receive
--
python-stdnum
--
To unsubscribe send an email to
python-stdnum-commits-unsubscribe@lists.arthurdejong.org or see
https://lists.arthurdejong.org/python-stdnum-commits/
- python-stdnum branch master updated. 1.7-23-g442aa82,
Commits of the python-stdnum project