DefinetlyNotAI/AlgoPy

View on GitHub
jupyter/validate.ipynb

Summary

Maintainability
Test Coverage
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "initial_id",
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import os\n",
    "from datetime import datetime\n",
    "\n",
    "\n",
    "class Validate:\n",
    "    @staticmethod\n",
    "    def this_email(email_address: str) -> bool:\n",
    "        if (1 <= len(email_address) <= 320) and \" \" not in email_address and \"@\" in email_address:\n",
    "            local_part, domain_part = email_address.rsplit(\"@\", 1)\n",
    "            if local_part and domain_part and \".\" in domain_part:\n",
    "                domain_labels = domain_part.split(\".\")\n",
    "                if all(label.isalnum() for label in domain_labels) and 2 <= len(domain_labels[-1]) <= 63:\n",
    "                    return True\n",
    "        return False\n",
    "\n",
    "    @staticmethod\n",
    "    def _url_by_parsing(url: str) -> dict | bool:\n",
    "        if not url:\n",
    "            return False\n",
    "        # Read TLDs from file\n",
    "        record_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'registered.tld.record')\n",
    "        with open(record_path, 'r') as file:\n",
    "            tlds = {line.strip().lower() for line in file.readlines()[1:]}\n",
    "\n",
    "        # Split the URL into components\n",
    "        if '://' not in url:\n",
    "            return False\n",
    "\n",
    "        protocol, rest = url.split('://', 1)\n",
    "        if '/' in rest:\n",
    "            hostname, filename = rest.split('/', 1)\n",
    "            filename = '/' + filename\n",
    "        else:\n",
    "            hostname = rest\n",
    "            filename = ''\n",
    "\n",
    "        # Extract TLD from hostname\n",
    "        tld = hostname.split('.')[-1].lower()\n",
    "        is_registered_tld = tld in tlds\n",
    "\n",
    "        if not hostname.startswith('www.'):\n",
    "            hostname = 'www.' + hostname\n",
    "\n",
    "        return {\n",
    "            'protocol': protocol,\n",
    "            'hostname': hostname,\n",
    "            'filename': filename,\n",
    "            'TLD': is_registered_tld\n",
    "        }\n",
    "\n",
    "    @classmethod\n",
    "    def this_url(cls, url: str, text_error: bool = False,\n",
    "                 enforce_https: bool = False) -> bool:\n",
    "        parsed_url = cls._url_by_parsing(url)\n",
    "        if not parsed_url:\n",
    "            return cls.__return_error('Invalid URL: Reason - URL is empty or does not contain a protocol', text_error)\n",
    "\n",
    "        if not cls.__validate_protocol(parsed_url['protocol'], enforce_https, text_error):\n",
    "            return False\n",
    "\n",
    "        if not cls.__validate_hostname(parsed_url['hostname'], text_error):\n",
    "            return False\n",
    "\n",
    "        if not cls.__validate_filename(parsed_url['filename'], text_error):\n",
    "            return False\n",
    "\n",
    "        if not parsed_url['TLD']:\n",
    "            return cls.__return_error('Invalid URL: Reason - TLD is not registered', text_error)\n",
    "\n",
    "        return True\n",
    "\n",
    "    @staticmethod\n",
    "    def __return_error(message: str, text_error: bool) -> bool:\n",
    "        return message if text_error else False\n",
    "\n",
    "    @classmethod\n",
    "    def __validate_protocol(cls, protocol: str, enforce_https: bool, text_error: bool) -> bool:\n",
    "        if protocol not in ['http', 'https']:\n",
    "            return cls.__return_error('Invalid URL: Reason - Protocol is not HTTP or HTTPS', text_error)\n",
    "        if enforce_https and protocol != 'https':\n",
    "            return cls.__return_error('Invalid URL: Reason - HTTPS protocol is enforced', text_error)\n",
    "        return True\n",
    "\n",
    "    @classmethod\n",
    "    def __validate_hostname(cls, hostname: str, text_error: bool) -> bool:\n",
    "        if len(hostname) > 253:\n",
    "            return cls.__return_error('Invalid URL: Reason - Hostname is too long', text_error)\n",
    "        if hostname.count('.') < 1:\n",
    "            return cls.__return_error('Invalid URL: Reason - Hostname does not contain a domain', text_error)\n",
    "        hostname_labels = hostname.split('.')\n",
    "        for label in hostname_labels:\n",
    "            if not all(c.isalnum() or c == '-' for c in label):\n",
    "                return cls.__return_error('Invalid URL: Reason - Invalid character in hostname', text_error)\n",
    "            if label.startswith('-') or label.endswith('-'):\n",
    "                return cls.__return_error('Invalid URL: Reason - Label starts or ends with a hyphen', text_error)\n",
    "            if label.isdigit():\n",
    "                return cls.__return_error('Invalid URL: Reason - Label is a number', text_error)\n",
    "        return True\n",
    "\n",
    "    @classmethod\n",
    "    def __validate_filename(cls, filename: str, text_error: bool) -> bool:\n",
    "        if len(filename) > 256:\n",
    "            return cls.__return_error('Invalid URL: Reason - Filename is too long', text_error)\n",
    "        if ' ' in filename:\n",
    "            return cls.__return_error('Invalid URL: Reason - Filename contains spaces', text_error)\n",
    "        return True\n",
    "\n",
    "    @staticmethod\n",
    "    def this_phone_number(phone_number: int | str) -> bool:\n",
    "        \"\"\"\n",
    "        Validates a phone number against a set of predefined formats.\n",
    "        Allow only digits, parentheses, hyphens, periods, and spaces.\n",
    "\n",
    "        Allowed formats:\n",
    "            \"(###)###-####\",\n",
    "            \"(###)-###-####\",\n",
    "            \"(###)###-###-####\",\n",
    "            \"(###)-###-###-####\",\n",
    "            \"(###)###-####-###\",\n",
    "            \"(###)-###-####-###\",\n",
    "            \"###-###-####\",\n",
    "            \"###-####-###\",\n",
    "            \"##########\",\n",
    "        Where # is a digit and - is a separator of any type allowed.\n",
    "\n",
    "        Args:\n",
    "            phone_number (int | str): The phone number to be validated.\n",
    "\n",
    "        Returns:\n",
    "            bool: True if the phone number is valid, False otherwise.\n",
    "        \"\"\"\n",
    "        phone_number = str(phone_number)\n",
    "        allowed_chars = set(\"0123456789()+-. \")\n",
    "        if not all(char in allowed_chars for char in phone_number):\n",
    "            return False\n",
    "\n",
    "        phone_number_list = list(phone_number)\n",
    "        for i, char in enumerate(phone_number_list):\n",
    "            if char.isdigit():\n",
    "                phone_number_list[i] = '#'\n",
    "            elif char == '+' or char == '.' or char == ' ':\n",
    "                phone_number_list[i] = '-'\n",
    "\n",
    "        formatted_phone_number = ''.join(phone_number_list)\n",
    "        valid_formats = [\n",
    "            \"(###)###-####\",\n",
    "            \"(###)-###-####\",\n",
    "            \"(###)###-###-####\",\n",
    "            \"(###)-###-###-####\",\n",
    "            \"(###)###-####-###\",\n",
    "            \"(###)-###-####-###\",\n",
    "            \"###-###-####\",\n",
    "            \"###-####-###\",\n",
    "            \"##########\",\n",
    "        ]\n",
    "\n",
    "        return formatted_phone_number in valid_formats\n",
    "\n",
    "    @staticmethod\n",
    "    def this_date(date: str, datetime_format: str = \"%Y-%m-%d\") -> bool:\n",
    "        r\"\"\"\n",
    "        Validates a date string.\n",
    "\n",
    "        The allowed date formats in the selected code are:\n",
    "\n",
    "        - `DD-MM-YYYY`\n",
    "        - `YYYY-MM-DD`\n",
    "\n",
    "        These formats are normalized to either `YYYY-MM-DD` or `DD-MM-YYYY` before validation.\n",
    "        Where `-` is a separator, and can be from the following set [-, /, \\, ].\n",
    "\n",
    "        Args:\n",
    "            date (str): The date string to be validated.\n",
    "            datetime_format (str): The format of the date string. Defaults to `\"%Y-%m-%d\"`. Always falls-back to `\"%d-%m-%Y\"`.\n",
    "\n",
    "        Returns:\n",
    "            bool: True if the date string is valid, False otherwise.\n",
    "        \"\"\"\n",
    "        if not date:\n",
    "            return False\n",
    "        date = date.replace(\"/\", \"-\")\n",
    "        date = date.replace(\"\\\\\", \"-\")\n",
    "        date = date.replace(\" \", \"-\")\n",
    "        try:\n",
    "            datetime.strptime(date, datetime_format)\n",
    "            return True\n",
    "        except ValueError:\n",
    "            try:\n",
    "                datetime.strptime(date, \"%d-%m-%Y\")\n",
    "                return True\n",
    "            except ValueError:\n",
    "                return False\n",
    "\n",
    "    class CreditCard:\n",
    "        def __init__(self):\n",
    "            \"\"\"\n",
    "            Validates a card number using the Luhn algorithm.\n",
    "            Specify in specifics inside the class.\n",
    "\n",
    "            Returns a boolean value if the card number is valid or not.\n",
    "            \"\"\"\n",
    "            pass\n",
    "\n",
    "        @classmethod\n",
    "        def __luhn_algorithm(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates a card number using the Luhn algorithm.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            if len(card_number) < 13 or len(card_number) > 19:\n",
    "                return False\n",
    "\n",
    "            num_list = [int(digit) for digit in card_number]\n",
    "            num_list.reverse()\n",
    "\n",
    "            total = sum(cls.__luhn_double(num) if i % 2 == 1 else num for i, num in enumerate(num_list))\n",
    "            return total % 10 == 0\n",
    "\n",
    "        @staticmethod\n",
    "        def __luhn_double(num: int) -> int:\n",
    "            \"\"\"\n",
    "            Doubles the number and subtracts 9 if the result is greater than 9.\n",
    "\n",
    "            Args:\n",
    "                num (int): The number to be doubled.\n",
    "\n",
    "            Returns:\n",
    "                int: The processed number.\n",
    "            \"\"\"\n",
    "            doubled = num * 2\n",
    "            return doubled - 9 if doubled > 9 else doubled\n",
    "\n",
    "        @classmethod\n",
    "        def american_express(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates American Express card numbers.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            return cls.__luhn_algorithm(card_number) and (\n",
    "                    str(card_number).startswith((\"34\", \"37\"))\n",
    "                    and 15 <= len(str(card_number)) <= 16\n",
    "            )\n",
    "\n",
    "        @classmethod\n",
    "        def china_unionpay(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates China UnionPay card numbers.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            return cls.__luhn_algorithm(card_number) and (\n",
    "                    str(card_number).startswith(\n",
    "                        (\n",
    "                            \"62\",\n",
    "                            \"64\",\n",
    "                            \"65\",\n",
    "                            \"66\",\n",
    "                            \"67\",\n",
    "                            \"68\",\n",
    "                            \"69\",\n",
    "                            \"92\",\n",
    "                            \"93\",\n",
    "                            \"94\",\n",
    "                            \"95\",\n",
    "                            \"96\",\n",
    "                            \"97\",\n",
    "                            \"98\",\n",
    "                            \"99\",\n",
    "                        )\n",
    "                    )\n",
    "                    and 16 <= len(str(card_number))\n",
    "            )\n",
    "\n",
    "        @classmethod\n",
    "        def dankort(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates Dankort card numbers.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            return (\n",
    "                    cls.__luhn_algorithm(card_number)\n",
    "                    and str(card_number).startswith(\"49\")\n",
    "                    and 16 <= len(str(card_number))\n",
    "            )\n",
    "\n",
    "        @classmethod\n",
    "        def diners_club(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates Diners Club International card numbers.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            return cls.__luhn_algorithm(card_number) and (\n",
    "                    str(card_number).startswith((\"36\", \"38\"))\n",
    "                    and 14 <= len(str(card_number)) <= 19\n",
    "            )\n",
    "\n",
    "        @classmethod\n",
    "        def discover(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates Discover card numbers.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            return cls.__luhn_algorithm(card_number) and (\n",
    "                    str(card_number).startswith(\n",
    "                        (\n",
    "                            \"6011\",\n",
    "                            \"6221\",\n",
    "                            \"6222\",\n",
    "                            \"6223\",\n",
    "                            \"623\",\n",
    "                            \"624\",\n",
    "                            \"625\",\n",
    "                            \"626\",\n",
    "                            \"627\",\n",
    "                            \"628\",\n",
    "                            \"641\",\n",
    "                            \"642\",\n",
    "                            \"643\",\n",
    "                            \"644\",\n",
    "                            \"645\",\n",
    "                            \"646\",\n",
    "                            \"647\",\n",
    "                            \"648\",\n",
    "                            \"649\",\n",
    "                            \"65\",\n",
    "                            \"66\",\n",
    "                            \"67\",\n",
    "                            \"68\",\n",
    "                            \"69\",\n",
    "                            \"71\",\n",
    "                            \"72\",\n",
    "                            \"73\",\n",
    "                            \"74\",\n",
    "                            \"75\",\n",
    "                            \"76\",\n",
    "                            \"77\",\n",
    "                            \"78\",\n",
    "                            \"79\",\n",
    "                        )\n",
    "                    )\n",
    "                    and 16 <= len(str(card_number))\n",
    "            )\n",
    "\n",
    "        @classmethod\n",
    "        def jcb(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates JCB card numbers.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            return (\n",
    "                    cls.__luhn_algorithm(card_number)\n",
    "                    and str(card_number).startswith(\"35\")\n",
    "                    and 16 <= len(str(card_number))\n",
    "            )\n",
    "\n",
    "        @classmethod\n",
    "        def maestro(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates Maestro card numbers.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            return cls.__luhn_algorithm(card_number) and (\n",
    "                    str(card_number).startswith(\n",
    "                        (\n",
    "                            \"50\",\n",
    "                            \"51\",\n",
    "                            \"52\",\n",
    "                            \"53\",\n",
    "                            \"54\",\n",
    "                            \"55\",\n",
    "                            \"56\",\n",
    "                            \"57\",\n",
    "                            \"58\",\n",
    "                            \"60\",\n",
    "                            \"61\",\n",
    "                            \"62\",\n",
    "                            \"63\",\n",
    "                            \"64\",\n",
    "                            \"65\",\n",
    "                            \"66\",\n",
    "                            \"67\",\n",
    "                            \"68\",\n",
    "                            \"69\",\n",
    "                            \"70\",\n",
    "                            \"71\",\n",
    "                            \"72\",\n",
    "                            \"73\",\n",
    "                            \"74\",\n",
    "                            \"75\",\n",
    "                            \"76\",\n",
    "                            \"77\",\n",
    "                            \"78\",\n",
    "                            \"79\",\n",
    "                        )\n",
    "                    )\n",
    "                    and 12 <= len(str(card_number)) <= 19\n",
    "            )\n",
    "\n",
    "        @classmethod\n",
    "        def mastercard(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates Mastercard card numbers.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            return (\n",
    "                    cls.__luhn_algorithm(card_number)\n",
    "                    and str(card_number).startswith((\"51\", \"52\", \"53\", \"54\", \"55\", \"56\", \"57\", \"58\", \"59\"))\n",
    "                    and 16 <= len(str(card_number))\n",
    "            )\n",
    "\n",
    "        @classmethod\n",
    "        def visa(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates Visa card numbers.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            return (\n",
    "                    cls.__luhn_algorithm(card_number)\n",
    "                    and str(card_number).startswith(\"4\")\n",
    "                    and 13 <= len(str(card_number)) <= 16\n",
    "            )\n",
    "\n",
    "        @classmethod\n",
    "        def visa_electron(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates Visa Electron card numbers.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            return (\n",
    "                    cls.__luhn_algorithm(card_number)\n",
    "                    and str(card_number).startswith((\"40\", \"41\", \"42\", \"43\", \"44\", \"45\", \"46\", \"47\", \"48\", \"49\"))\n",
    "                    and 16 <= len(str(card_number))\n",
    "            )\n",
    "\n",
    "        @classmethod\n",
    "        def v_pay(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates V Pay card numbers.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            return (\n",
    "                    cls.__luhn_algorithm(card_number)\n",
    "                    and str(str(card_number)).startswith(\"28\")\n",
    "                    and 16 <= len(str(str(card_number)))\n",
    "            )\n",
    "\n",
    "        @classmethod\n",
    "        def any(cls, card_number: str) -> bool:\n",
    "            \"\"\"\n",
    "            Validates any card number just by passing it to the Luhn algorithm.\n",
    "\n",
    "            Args:\n",
    "                card_number (str): The card number to be validated.\n",
    "\n",
    "            Returns:\n",
    "                bool: True if the card number is valid, False otherwise.\n",
    "            \"\"\"\n",
    "            return cls.__luhn_algorithm(card_number)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}