lists.arthurdejong.org
RSS feed

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



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/