pax_global_header00006660000000000000000000000064142471617140014521gustar00rootroot0000000000000052 comment=9c35f185c0d44c3cb1c7433c66e3dfbb921e5e54 validators-0.20.0/000077500000000000000000000000001424716171400137505ustar00rootroot00000000000000validators-0.20.0/.github/000077500000000000000000000000001424716171400153105ustar00rootroot00000000000000validators-0.20.0/.github/workflows/000077500000000000000000000000001424716171400173455ustar00rootroot00000000000000validators-0.20.0/.github/workflows/main.yml000066400000000000000000000017371424716171400210240ustar00rootroot00000000000000name: GH on: pull_request: branches: '*' push: branches: 'master' tags: '*' jobs: CI: runs-on: ubuntu-latest strategy: max-parallel: 8 matrix: python-version: [3.5, 3.6, 3.7, 3.8, 3.9, 3.10] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Pip cache uses: actions/cache@v2 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements/*.txt') }} restore-keys: | ${{ runner.os }}-pip- - name: Install dependencies run: pip install -e ".[test]" - name: Lint run: | isort --recursive --diff validators tests && isort --recursive --check-only validators tests flake8 validators tests - name: Test run: py.test --doctest-glob="*.rst" --doctest-modules --ignore=setup.py validators-0.20.0/.gitignore000066400000000000000000000005071424716171400157420ustar00rootroot00000000000000*.py[cod] # C extensions *.so # Packages *.egg *.egg-info dist build eggs parts bin var sdist develop-eggs .installed.cfg lib lib64 __pycache__ docs/_build # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox nosetests.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject validators-0.20.0/.isort.cfg000066400000000000000000000002001424716171400156370ustar00rootroot00000000000000[settings] known_first_party=sqlalchemy_utils,tests line_length=79 multi_line_output=3 not_skip=__init__.py order_by_type=false validators-0.20.0/.travis.yml000066400000000000000000000006041424716171400160610ustar00rootroot00000000000000language: python matrix: include: - python: 3.5 - python: 3.6 - python: 3.7 dist: xenial sudo: true - python: pypy3 install: - pip install -e ".[test]" script: - isort --recursive --diff validators tests && isort --recursive --check-only validators tests - flake8 validators tests - py.test --doctest-glob="*.rst" --doctest-modules --ignore=setup.py validators-0.20.0/CHANGES.rst000066400000000000000000000134161424716171400155570ustar00rootroot00000000000000Changelog --------- 0.20.0 (2022-06-05) ^^^^^^^^^^^^^^^^^^^ - Added ipv4 digit lenghts validation (#191, pull request courtesy of Norbiox) - Fixes error with international URLs that have more than 2 hyphens (#184, pull request courtesy of automationator) 0.19.0 (2022-05-04) ^^^^^^^^^^^^^^^^^^^ - Dropped py34 support - Improve IPv6 validation (#201, pull request courtesy of SimonIT) 0.18.2 (2020-12-18) ^^^^^^^^^^^^^^^^^^^ - Implement actual validation for old style BTC addresses including checksumming (#182, pull request courtesy of tpatja) - Use a regex to guesstimate validity of new segwit BTC addresses (#182, pull request courtesy of tpatja) 0.18.1 (2020-09-03) ^^^^^^^^^^^^^^^^^^^ - Made uuid validator accept UUID objects (#174, pull request courtesy of Letsch22) 0.18.0 (2020-08-19) ^^^^^^^^^^^^^^^^^^^ - Added bitcoin address validator (#166, pull request courtesy of daveusa31) 0.17.1 (2020-08-03) ^^^^^^^^^^^^^^^^^^^ - Fixed python_requires using twine 0.17.0 (2020-08-02) ^^^^^^^^^^^^^^^^^^^ - Added python_requires='>=3.4' to setup.py (#163, pull request courtesy of vphilippon) - Fixed URL validator ip_last_octet regex (#145, pull request courtesy of ghost) 0.16.0 (2020-07-16) ^^^^^^^^^^^^^^^^^^^ - Added support for emojis and more IDNA URLs (#161, pull request courtesy of automationator) 0.15.0 (2020-05-07) ^^^^^^^^^^^^^^^^^^^ - Added bank card validators (#157, pull request courtesy of TimonPeng) 0.14.3 (2020-02-04) ^^^^^^^^^^^^^^^^^^^ - Handle None values gracefully in domain validator (#144, pull request courtesy reahaas) - Local part of the email address should be less or equal than 64 bytes (#147, pull request courtesy mondeja) - Removed py27 support - Removed pypy2 support 0.14.2 (2020-01-24) ^^^^^^^^^^^^^^^^^^^ - Made domain validation case-insensitive (#136, pull request courtesy ehmkah) 0.14.1 (2019-12-04) ^^^^^^^^^^^^^^^^^^^ - Updated domain validator regex to not allow numeric only TLDs (#133, pull request courtesy jmeridth) - Allow for idna encoded domains (#133, pull request courtesy jmeridth) 0.14.0 (2019-08-21) ^^^^^^^^^^^^^^^^^^^ - Added new validators ``ipv4_cidr``, ``ipv6_cidr`` (#117, pull request courtesy woodruffw) 0.13.0 (2019-05-20) ^^^^^^^^^^^^^^^^^^^ - Added new validator: ``es_doi``, ``es_nif``, ``es_cif``, ``es_nie`` (#121, pull request courtesy kingbuzzman) 0.12.6 (2019-05-08) ^^^^^^^^^^^^^^^^^^^ - Fixed domain validator for single character domains (#118, pull request courtesy kingbuzzman) 0.12.5 (2019-04-15) ^^^^^^^^^^^^^^^^^^^ - Fixed py37 support (#113, pull request courtesy agiletechnologist) 0.12.4 (2019-01-02) ^^^^^^^^^^^^^^^^^^^ - Use inspect.getfullargspec() in py3 (#110, pull request courtesy riconnon) 0.12.3 (2018-11-13) ^^^^^^^^^^^^^^^^^^^ - Added `allow_temporal_ssn` parameter to fi_ssn validator (#97, pull request courtesy quantus) - Remove py33 support 0.12.2 (2018-06-03) ^^^^^^^^^^^^^^^^^^^ - Fixed IPv4 formatted IP address returning True on ipv6 (#85, pull request courtesy johndlong) - Fixed IPv6 address parsing (#83, pull request courtesy JulianKahnert) - Fixed domain validator for international domains and certain edge cases (#76, pull request courtesy Ni-Knight) 0.12.1 (2018-01-30) ^^^^^^^^^^^^^^^^^^^ - Fixed IDNA encoded TLDs in domain validator (#75, pull request courtesy piewpiew) - Fixed URL validator for URLs with invalid characters in userinfo part (#69, pull request courtesy timb07) 0.12.0 (2017-06-03) ^^^^^^^^^^^^^^^^^^^ - Added hash validators for md5, sha1, sha224, sha256 and sha512 - Made ipv6 validator support IPv4-mapped IPv6 addresses 0.11.3 (2017-03-27) ^^^^^^^^^^^^^^^^^^^ - Fixed URL validator for URLs containing localhost (#51, pull request courtesy vladimirdotk) 0.11.2 (2017-01-08) ^^^^^^^^^^^^^^^^^^^ - Fixed URL validator for urls with query parameters but without path (#44, pull request courtesy zjjw) 0.11.1 (2016-11-19) ^^^^^^^^^^^^^^^^^^^ - Fixed pyp2rpm build problem (#37, pull request courtesy BOPOHA) 0.11.0 (2016-08-30) ^^^^^^^^^^^^^^^^^^^ - Fixed public url validation (#29) - Made URL validator case insensitive (#27) - Drop Python 2.6 support 0.10.3 (2016-06-13) ^^^^^^^^^^^^^^^^^^^ - Added ``public`` parameter to url validator (#26, pull request courtesy Iconceicao) 0.10.2 (2016-06-11) ^^^^^^^^^^^^^^^^^^^ - Fixed various URL validation issues 0.10.1 (2016-04-09) ^^^^^^^^^^^^^^^^^^^ - Fixed domain name validation for numeric domain names (#21, pull request courtesy shaunpud) - Fixed IBAN validation for Norwegian and Belgian IBANs (#17, pull request courtesy mboelens91) 0.10.0 (2016-01-09) ^^^^^^^^^^^^^^^^^^^ - Added support for internationalized domain names in ``domain`` validator 0.9.0 (2015-10-10) ^^^^^^^^^^^^^^^^^^ - Added new validator: ``domain`` - Added flake8 and isort checks in travis config 0.8.0 (2015-06-24) ^^^^^^^^^^^^^^^^^^ - Added new validator: ``iban`` 0.7.0 (2014-09-07) ^^^^^^^^^^^^^^^^^^ - Fixed errors in code examples. - Fixed ``TypeError`` when using ``between`` validator with ``datetime`` objects like in the code example. - Changed validators to always return ``True`` instead of a truthy object when the validation succeeds. - Fixed ``truthy`` validator to work like it's name suggests. Previously it worked like ``falsy``. 0.6.0 (2014-06-25) ^^^^^^^^^^^^^^^^^^ - Added new validator: ``slug`` 0.5.0 (2013-10-31) ^^^^^^^^^^^^^^^^^^ - Renamed ``finnish_business_id`` to ``fi_business_id`` - Added new validator: ``fi_ssn`` 0.4.0 (2013-10-29) ^^^^^^^^^^^^^^^^^^ - Added new validator: ``finnish_business_id`` 0.3.0 (2013-10-27) ^^^^^^^^^^^^^^^^^^ - ``number_range`` -> ``between`` 0.2.0 (2013-10-22) ^^^^^^^^^^^^^^^^^^ - Various new validators: ``ipv4``, ``ipv6``, ``length``, ``number_range``, ``mac_address``, ``url``, ``uuid`` 0.1.0 (2013-10-18) ^^^^^^^^^^^^^^^^^^ - Initial public release validators-0.20.0/LICENSE000066400000000000000000000021011424716171400147470ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2013-2014 Konsta Vesterinen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. validators-0.20.0/MANIFEST.in000066400000000000000000000003011424716171400155000ustar00rootroot00000000000000include CHANGES.rst LICENSE README.rst recursive-include tests * recursive-exclude tests *.pyc recursive-include docs * recursive-exclude docs *.pyc prune docs/_build exclude docs/_themes/.git validators-0.20.0/README.rst000066400000000000000000000020151424716171400154350ustar00rootroot00000000000000validators ========== |Build Status| |Version Status| |Downloads| Python data validation for Humans. Python has all kinds of data validation tools, but every one of them seems to require defining a schema or form. I wanted to create a simple validation library where validating a simple value does not require defining a form or a schema. .. code-block:: python >>> import validators >>> validators.email('someone@example.com') True Resources --------- - `Documentation `_ - `Issue Tracker `_ - `Code `_ .. |Build Status| image:: https://travis-ci.org/kvesteri/validators.svg?branch=master :target: https://travis-ci.org/kvesteri/validators .. |Version Status| image:: https://img.shields.io/pypi/v/validators.svg :target: https://pypi.python.org/pypi/validators/ .. |Downloads| image:: https://img.shields.io/pypi/dm/validators.svg :target: https://pypi.python.org/pypi/validators/ validators-0.20.0/docs/000077500000000000000000000000001424716171400147005ustar00rootroot00000000000000validators-0.20.0/docs/Makefile000066400000000000000000000151721424716171400163460ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/validators.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/validators.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/validators" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/validators" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." validators-0.20.0/docs/conf.py000066400000000000000000000206451424716171400162060ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # validators documentation build configuration file, created by # sphinx-quickstart on Mon Oct 21 12:30:12 2013. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('..')) from validators import __version__ # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.mathjax', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'validators' copyright = u'2013-2014, Konsta Vesterinen' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = __version__ # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'validatorsdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'validators.tex', u'validators Documentation', u'Konsta Vesterinen', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'validators', u'validators Documentation', [u'Konsta Vesterinen'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'validators', u'validators Documentation', u'Konsta Vesterinen', 'validators', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'http://docs.python.org/': None} validators-0.20.0/docs/index.rst000066400000000000000000000066241424716171400165510ustar00rootroot00000000000000validators ========== Python Data Validation for Humans™. Why? ==== Python has all kinds of validation tools, but every one of them requires defining a schema. I wanted to create a simple validation library where validating a simple value does not require defining a form or a schema. Apparently `some other guys have felt the same way`_. .. _some other guys have felt the same way: http://opensourcehacker.com/2011/07/07/generic-python-validation-frameworks/ Often I've had for example a case where I just wanted to check if given string is an email. With ``validators`` this use case becomes as easy as:: >>> import validators >>> validators.email('someone@example.com') True Installation ============ You can install ``validators`` using pip:: pip install validators Currently ``validators`` supports python versions 2.7, 3.3, 3.4, 3.5, 3.6, 3.7 and PyPy. Basic validators ================ Each validator in ``validators`` is a simple function that takes the value to validate and possibly some additional key-value arguments. Each function returns ``True`` when validation succeeds and :class:`~validators.utils.ValidationFailure` object when validation fails. :class:`~validators.utils.ValidationFailure` class implements ``__bool__`` method so you can easily check if validation failed:: >>> if not validators.email('some_bogus_email@@@'): ... # Do something here ... pass :class:`~validators.utils.ValidationFailure` object also holds all the arguments passed to original function:: >>> result = validators.between(3, min=5) >>> result.value 3 >>> result.min 5 between ------- .. module:: validators.between .. autofunction:: between btc_address ------ .. module:: validators.btc_address .. autofunction:: btc_address domain ------ .. module:: validators.domain .. autofunction:: domain email ----- .. module:: validators.email .. autofunction:: email iban ---- .. module:: validators.iban .. autofunction:: iban ipv4 ---- .. module:: validators.ip_address .. autofunction:: ipv4 ipv6 ---- .. autofunction:: ipv6 length ------ .. module:: validators.length .. autofunction:: length mac_address ----------- .. module:: validators.mac_address .. autofunction:: mac_address md5 ----------- .. module:: validators.hashes .. autofunction:: md5 sha1 ----------- .. module:: validators.hashes .. autofunction:: sha1 sha224 ----------- .. module:: validators.hashes .. autofunction:: sha224 sha256 ----------- .. module:: validators.hashes .. autofunction:: sha256 sha512 ----------- .. module:: validators.hashes .. autofunction:: sha512 slug ---- .. module:: validators.slug .. autofunction:: slug truthy ------ .. module:: validators.truthy .. autofunction:: truthy url --- .. module:: validators.url .. autofunction:: url uuid ---- .. module:: validators.uuid .. autofunction:: uuid i18n validators =============== Spanish ------- .. module:: validators.i18n.es es_doi ^^^^^^ .. autofunction:: es_doi es_nif ^^^^^^ .. autofunction:: es_nif es_nie ^^^^^^ .. autofunction:: es_nie es_cif ^^^^^^ .. autofunction:: es_cif Finnish ------- .. module:: validators.i18n.fi fi_business_id ^^^^^^^^^^^^^^ .. autofunction:: fi_business_id fi_ssn ^^^^^^ .. autofunction:: fi_ssn Internals ========= validator --------- .. module:: validators.utils .. autoclass:: ValidationFailure .. autofunction:: validator validators-0.20.0/docs/make.bat000066400000000000000000000150651424716171400163140ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\validators.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\validators.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end validators-0.20.0/setup.py000066400000000000000000000036241424716171400154670ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ validators ---------- Python Data Validation for Humans™. """ from setuptools import setup, find_packages import os import re import sys PY3 = sys.version_info[0] == 3 HERE = os.path.dirname(os.path.abspath(__file__)) def get_version(): filename = os.path.join(HERE, 'validators', '__init__.py') with open(filename) as f: contents = f.read() pattern = r"^__version__ = '(.*?)'$" return re.search(pattern, contents, re.MULTILINE).group(1) extras_require = { 'test': [ 'pytest>=2.2.3', 'flake8>=2.4.0', 'isort>=4.2.2' ], } install_requires = [ 'decorator>=3.4.0', ] setup( name='validators', version=get_version(), url='https://github.com/kvesteri/validators', license='MIT', author='Konsta Vesterinen', author_email='konsta@fastmonkeys.com', description='Python Data Validation for Humans™.', long_description=__doc__, packages=find_packages('.', exclude=['tests', 'tests.*']), zip_safe=False, include_package_data=True, platforms='any', install_requires=install_requires, build_requires=install_requires, extras_require=extras_require, classifiers=[ 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development :: Libraries :: Python Modules' ], python_requires='>=3.4' ) validators-0.20.0/tests/000077500000000000000000000000001424716171400151125ustar00rootroot00000000000000validators-0.20.0/tests/__init__.py000066400000000000000000000000001424716171400172110ustar00rootroot00000000000000validators-0.20.0/tests/i18n/000077500000000000000000000000001424716171400156715ustar00rootroot00000000000000validators-0.20.0/tests/i18n/__init__.py000066400000000000000000000000001424716171400177700ustar00rootroot00000000000000validators-0.20.0/tests/i18n/test_es.py000066400000000000000000000041171424716171400177140ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import ValidationFailure from validators.i18n.es import es_cif, es_doi, es_nie, es_nif @pytest.mark.parametrize(('value',), [ ('B25162520',), ('U4839822F',), ('B96817697',), ('P7067074J',), ('Q7899705C',), ('C75098681',), ('G76061860',), ('C71345375',), ('G20558169',), ('U5021960I',), ]) def test_returns_true_on_valid_cif(value): assert es_cif(value) @pytest.mark.parametrize(('value',), [ ('12345',), ('ABCDEFGHI',), ('Z5021960I',), ]) def test_returns_false_on_invalid_cif(value): result = es_cif(value) assert isinstance(result, ValidationFailure) @pytest.mark.parametrize(('value',), [ ('X0095892M',), ('X8868108K',), ('X2911154K',), ('Y2584969J',), ('X7536157T',), ('Y5840388N',), ('Z2915723H',), ('Y4002236C',), ('X7750702R',), ('Y0408759V',), ]) def test_returns_true_on_valid_nie(value): assert es_nie(value) @pytest.mark.parametrize(('value',), [ ('K0000023T',), ('L0000024R',), ('M0000025W',), ('00000026A',), ('00000027G',), ('00000028M',), ('00000029Y',), ('00000030F',), ('00000031P',), ('00000032D',), ('00000033X',), ('00000034B',), ('00000035N',), ('00000036J',), ('00000037Z',), ('00000038S',), ('00000039Q',), ('00000040V',), ('00000041H',), ('00000042L',), ('00000043C',), ('00000044K',), ('00000045E',), ]) def test_returns_true_on_valid_nif(value): assert es_nif(value) @pytest.mark.parametrize(('value',), [ ('12345',), ('X0000000T',), ('00000000T',), ('00000001R',), ]) def test_returns_false_on_invalid_nif(value): result = es_nif(value) assert isinstance(result, ValidationFailure) @pytest.mark.parametrize(('value',), [ # CIFs ('B25162520',), ('U4839822F',), ('B96817697',), # NIEs ('X0095892M',), ('X8868108K',), ('X2911154K',), # NIFs ('26643189N',), ('07060225F',), ('49166693F',), ]) def test_returns_true_on_valid_doi(value): assert es_doi(value) validators-0.20.0/tests/i18n/test_fi.py000066400000000000000000000027301424716171400177020ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import ValidationFailure from validators.i18n.fi import fi_business_id, fi_ssn @pytest.mark.parametrize(('value',), [ ('2336509-6',), # Supercell ('0112038-9',), # Fast Monkeys ('2417581-7',), # Nokia ]) def test_returns_true_on_valid_business_id(value): assert fi_business_id(value) @pytest.mark.parametrize(('value',), [ (None,), ('',), ('1233312312',), ('1333333-8',), ('1231233-9',), ]) def test_returns_failed_validation_on_invalid_business_id(value): assert isinstance(fi_business_id(value), ValidationFailure) @pytest.mark.parametrize(('value',), [ ('010190-002R',), ('010101-0101',), ('010101+0101',), ('010101A0101',), ('010190-900P',), ]) def test_returns_true_on_valid_ssn(value): assert fi_ssn(value) @pytest.mark.parametrize(('value',), [ (None,), ('',), ('010190-001P',), # Too low serial ('010190-000N',), # Too low serial ('000190-0023',), # Invalid day ('010090-002X',), # Invalid month ('010190-002r',), # Invalid checksum ('101010-0102',), ('10a010-0101',), ('101010-0\xe401',), ('101010b0101',) ]) def test_returns_failed_validation_on_invalid_ssn(value): assert isinstance(fi_ssn(value), ValidationFailure) def test_returns_failed_validation_on_temporal_ssn_when_not_allowed(): assert isinstance( fi_ssn('010190-900P', allow_temporal_ssn=False), ValidationFailure ) validators-0.20.0/tests/test_between.py000066400000000000000000000015371424716171400201620ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest import validators @pytest.mark.parametrize(('value', 'min', 'max'), [ (12, 11, 13), (12, None, 14), (12, 11, None), (12, 12, 12) ]) def test_returns_true_on_valid_range(value, min, max): assert validators.between(value, min=min, max=max) @pytest.mark.parametrize(('value', 'min', 'max'), [ (12, 13, 12), (12, None, None), ]) def test_raises_assertion_error_for_invalid_args(value, min, max): with pytest.raises(AssertionError): assert validators.between(value, min=min, max=max) @pytest.mark.parametrize(('value', 'min', 'max'), [ (12, 13, 14), (12, None, 11), (12, 13, None) ]) def test_returns_failed_validation_on_invalid_range(value, min, max): result = validators.between(value, min=min, max=max) assert isinstance(result, validators.ValidationFailure) validators-0.20.0/tests/test_btc_address.py000066400000000000000000000017401424716171400210020ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import btc_address, ValidationFailure @pytest.mark.parametrize( 'value', [ # P2PKH (Pay-to-PubkeyHash) type '1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2', # P2SH (Pay to script hash) type '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy', # Bech32/segwit type 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq', 'bc1qc7slrfxkknqcq2jevvvkdgvrt8080852dfjewde450xdlk4ugp7szw5tk9', ], ) def test_returns_true_on_valid_btc_address(value): assert btc_address(value) @pytest.mark.parametrize( 'value', [ 'ff3Cwgr2g7vsi1bXDUkpEnVoRLA9w4FZfC69', 'b3Cgwgr2g7vsi1bXyjyDUkphEnVoRLA9w4FZfC69', # incorrect header '1BvBMsEYstWetqTFn5Au4m4GFg7xJaNVN2', # incorrect checksum '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLz', ], ) def test_returns_failed_validation_on_invalid_btc_address(value): assert isinstance(btc_address(value), ValidationFailure) validators-0.20.0/tests/test_card.py000066400000000000000000000072631424716171400174440ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import ( amex, card_number, diners, discover, jcb, mastercard, unionpay, ValidationFailure, visa ) visa_cards = [ '4242424242424242', '4000002760003184' ] mastercard_cards = [ '5555555555554444', '2223003122003222' ] amex_cards = [ '378282246310005', '371449635398431' ] unionpay_cards = [ '6200000000000005' ] diners_cards = [ '3056930009020004', '36227206271667' ] jcb_cards = [ '3566002020360505' ] discover_cards = [ '6011111111111117', '6011000990139424' ] @pytest.mark.parametrize( "value", visa_cards + mastercard_cards + amex_cards + unionpay_cards + diners_cards + jcb_cards + discover_cards, ) def test_returns_true_on_valid_card_number(value): assert card_number(value) @pytest.mark.parametrize('value', [ '4242424242424240', '4000002760003180', '400000276000318X' ]) def test_returns_failed_on_valid_card_number(value): assert isinstance(card_number(value), ValidationFailure) @pytest.mark.parametrize('value', visa_cards) def test_returns_true_on_valid_visa(value): assert visa(value) @pytest.mark.parametrize( "value", mastercard_cards + amex_cards + unionpay_cards + diners_cards + jcb_cards + discover_cards, ) def test_returns_failed_on_valid_visa(value): assert isinstance(visa(value), ValidationFailure) @pytest.mark.parametrize('value', mastercard_cards) def test_returns_true_on_valid_mastercard(value): assert mastercard(value) @pytest.mark.parametrize( "value", visa_cards + amex_cards + unionpay_cards + diners_cards + jcb_cards + discover_cards, ) def test_returns_failed_on_valid_mastercard(value): assert isinstance(mastercard(value), ValidationFailure) @pytest.mark.parametrize('value', amex_cards) def test_returns_true_on_valid_amex(value): assert amex(value) @pytest.mark.parametrize( "value", visa_cards + mastercard_cards + unionpay_cards + diners_cards + jcb_cards + discover_cards, ) def test_returns_failed_on_valid_amex(value): assert isinstance(amex(value), ValidationFailure) @pytest.mark.parametrize('value', unionpay_cards) def test_returns_true_on_valid_unionpay(value): assert unionpay(value) @pytest.mark.parametrize( "value", visa_cards + mastercard_cards + amex_cards + diners_cards + jcb_cards + discover_cards, ) def test_returns_failed_on_valid_unionpay(value): assert isinstance(unionpay(value), ValidationFailure) @pytest.mark.parametrize('value', diners_cards) def test_returns_true_on_valid_diners(value): assert diners(value) @pytest.mark.parametrize( "value", visa_cards + mastercard_cards + amex_cards + unionpay_cards + jcb_cards + discover_cards, ) def test_returns_failed_on_valid_diners(value): assert isinstance(diners(value), ValidationFailure) @pytest.mark.parametrize('value', jcb_cards) def test_returns_true_on_valid_jcb(value): assert jcb(value) @pytest.mark.parametrize( "value", visa_cards + mastercard_cards + amex_cards + unionpay_cards + diners_cards + discover_cards, ) def test_returns_failed_on_valid_jcb(value): assert isinstance(jcb(value), ValidationFailure) @pytest.mark.parametrize('value', discover_cards) def test_returns_true_on_valid_discover(value): assert discover(value) @pytest.mark.parametrize( "value", visa_cards + mastercard_cards + amex_cards + unionpay_cards + diners_cards + jcb_cards, ) def test_returns_failed_on_valid_discover(value): assert isinstance(discover(value), ValidationFailure) validators-0.20.0/tests/test_domain.py000066400000000000000000000016231424716171400177740ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import domain, ValidationFailure @pytest.mark.parametrize('value', [ 'example.com', 'xn----gtbspbbmkef.xn--p1ai', 'underscore_subdomain.example.com', 'something.versicherung', 'someThing.versicherung', '11.com', '3.cn', 'a.cn', 'sub1.sub2.sample.co.uk', 'somerandomexample.xn--fiqs8s', 'kräuter.com', 'über.com' ]) def test_returns_true_on_valid_domain(value): assert domain(value) @pytest.mark.parametrize('value', [ 'example.com/', 'example.com:4444', 'example.-com', 'example.', '-example.com', 'example-.com', '_example.com', 'example_.com', 'example', 'a......b.com', 'a.123', '123.123', '123.123.123', '123.123.123.123' ]) def test_returns_failed_validation_on_invalid_domain(value): assert isinstance(domain(value), ValidationFailure) validators-0.20.0/tests/test_email.py000066400000000000000000000024431424716171400176150ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import email, ValidationFailure @pytest.mark.parametrize(('value', 'whitelist'), [ ('email@here.com', None), ('weirder-email@here.and.there.com', None), ('email@[127.0.0.1]', None), ('example@valid-----hyphens.com', None), ('example@valid-with-hyphens.com', None), ('test@domain.with.idn.tld.उदाहरण.परीक्षा', None), ('email@localhost', None), ('email@localdomain', ['localdomain']), ('"test@test"@example.com', None), ('"\\\011"@here.com', None), ]) def test_returns_true_on_valid_email(value, whitelist): assert email(value, whitelist=whitelist) @pytest.mark.parametrize(('value',), [ (None,), ('',), ('abc',), ('abc@',), ('abc@bar',), ('a @x.cz',), ('abc@.com',), ('something@@somewhere.com',), ('email@127.0.0.1',), ('example@invalid-.com',), ('example@-invalid.com',), ('example@inv-.alid-.com',), ('example@inv-.-alid.com',), ( 'john56789.john56789.john56789.john56789.john56789.john56789.john5' '@example.com', ), # Quoted-string format (CR not allowed) ('"\\\012"@here.com',), ]) def test_returns_failed_validation_on_invalid_email(value): assert isinstance(email(value), ValidationFailure) validators-0.20.0/tests/test_extremes.py000066400000000000000000000014561424716171400203650ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import Max, Min @pytest.mark.parametrize(('value',), [ (None,), ('',), (12,), (Min,), ]) def test_max_is_greater_than_every_other_value(value): assert value < Max assert Max > value def test_max_is_not_greater_than_itself(): assert not (Max < Max) def test_other_comparison_methods_for_max(): assert Max <= Max assert Max == Max assert not (Max != Max) @pytest.mark.parametrize(('value',), [ (None,), ('',), (12,), (Max,), ]) def test_min_is_smaller_than_every_other_value(value): assert value > Min def test_min_is_not_greater_than_itself(): assert not (Min < Min) def test_other_comparison_methods_for_min(): assert Min <= Min assert Min == Min assert not (Min != Min) validators-0.20.0/tests/test_iban.py000066400000000000000000000007341424716171400174400ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest import validators @pytest.mark.parametrize('value', [ 'GB82WEST12345698765432', 'NO9386011117947' ]) def test_returns_true_on_valid_iban(value): assert validators.iban(value) @pytest.mark.parametrize('value', [ 'GB81WEST12345698765432', 'NO9186011117947' ]) def test_returns_failed_validation_on_invalid_iban(value): result = validators.iban(value) assert isinstance(result, validators.ValidationFailure) validators-0.20.0/tests/test_ipv4.py000066400000000000000000000011161424716171400174040ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import ipv4, ipv6, ValidationFailure @pytest.mark.parametrize(('address',), [ ('127.0.0.1',), ('123.5.77.88',), ('12.12.12.12',), ]) def test_returns_true_on_valid_ipv4_address(address): assert ipv4(address) assert not ipv6(address) @pytest.mark.parametrize(('address',), [ ('abc.0.0.1',), ('1278.0.0.1',), ('127.0.0.abc',), ('900.200.100.75',), ('0127.0.0.1',), ]) def test_returns_failed_validation_on_invalid_ipv4_address(address): assert isinstance(ipv4(address), ValidationFailure) validators-0.20.0/tests/test_ipv4_cidr.py000066400000000000000000000011141424716171400204030ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import ipv4_cidr, ipv6_cidr, ValidationFailure @pytest.mark.parametrize(('cidr',), [ ('127.0.0.1/0',), ('123.5.77.88/8',), ('12.12.12.12/32',), ]) def test_returns_true_on_valid_ipv4_cidr(cidr): assert ipv4_cidr(cidr) assert not ipv6_cidr(cidr) @pytest.mark.parametrize(('cidr',), [ ('abc.0.0.1',), ('1.1.1.1',), ('1.1.1.1/-1',), ('1.1.1.1/33',), ('1.1.1.1/foo',), ]) def test_returns_failed_validation_on_invalid_ipv4_cidr(cidr): assert isinstance(ipv4_cidr(cidr), ValidationFailure) validators-0.20.0/tests/test_ipv6.py000066400000000000000000000017431424716171400174140ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import ipv4, ipv6, ValidationFailure @pytest.mark.parametrize(('address',), [ ('::',), ('::1',), ('1::',), ('dead:beef:0:0:0:0000:42:1',), ('abcd:ef::42:1',), ('0:0:0:0:0:ffff:1.2.3.4',), ('::192.168.30.2',), ('0000:0000:0000:0000:0000::',), ('0:a:b:c:d:e:f::',), ]) def test_returns_true_on_valid_ipv6_address(address): assert ipv6(address) assert not ipv4(address) @pytest.mark.parametrize(('address',), [ ('abc.0.0.1',), ('abcd:1234::123::1',), ('1:2:3:4:5:6:7:8:9',), ('1:2:3:4:5:6:7:8::',), ('1:2:3:4:5:6:7::8:9',), ('abcd::1ffff',), ('1111:',), (':8888',), (':1.2.3.4',), ('18:05',), (':',), (':1:2:',), (':1:2::',), ('::1:2::',), ('8::1:2::9',), ('02001:0000:1234:0000:0000:C1C0:ABCD:0876',), ]) def test_returns_failed_validation_on_invalid_ipv6_address(address): assert isinstance(ipv6(address), ValidationFailure) validators-0.20.0/tests/test_ipv6_cidr.py000066400000000000000000000013451424716171400204130ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import ipv4_cidr, ipv6_cidr, ValidationFailure @pytest.mark.parametrize(('cidr',), [ ('::1/0',), ('dead:beef:0:0:0:0:42:1/8',), ('abcd:ef::42:1/32',), ('0:0:0:0:0:ffff:1.2.3.4/64',), ('::192.168.30.2/128',), ]) def test_returns_true_on_valid_ipv6_cidr(cidr): assert ipv6_cidr(cidr) assert not ipv4_cidr(cidr) @pytest.mark.parametrize(('cidr',), [ ('abc.0.0.1',), ('abcd:1234::123::1',), ('1:2:3:4:5:6:7:8:9',), ('abcd::1ffff',), ('1.1.1.1',), ('::1',), ('::1/129',), ('::1/-1',), ('::1/foo',), ]) def test_returns_failed_validation_on_invalid_ipv6_cidr(cidr): assert isinstance(ipv6_cidr(cidr), ValidationFailure) validators-0.20.0/tests/test_length.py000066400000000000000000000017341424716171400200110ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest import validators @pytest.mark.parametrize(('value', 'min', 'max'), [ ('password', 2, 10), ('password', None, 10), ('password', 2, None), ('password', 8, 8) ]) def test_returns_true_on_valid_length(value, min, max): assert validators.length(value, min=min, max=max) @pytest.mark.parametrize(('value', 'min', 'max'), [ ('something', 13, 12), ('something', -1, None), ('something', -1, None), ('something', -3, -2) ]) def test_raises_assertion_error_for_invalid_args(value, min, max): with pytest.raises(AssertionError): assert validators.length(value, min=min, max=max) @pytest.mark.parametrize(('value', 'min', 'max'), [ ('something', 13, 14), ('something', None, 6), ('something', 13, None) ]) def test_returns_failed_validation_on_invalid_range(value, min, max): assert isinstance( validators.length(value, min=min, max=max), validators.ValidationFailure ) validators-0.20.0/tests/test_mac_address.py000066400000000000000000000010311424716171400207630ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import mac_address, ValidationFailure @pytest.mark.parametrize(('address',), [ ('01:23:45:67:ab:CD',), ]) def test_returns_true_on_valid_mac_address(address): assert mac_address(address) @pytest.mark.parametrize(('address',), [ ('00:00:00:00:00',), ('01:23:45:67:89:',), ('01:23:45:67:89:gh',), ('123:23:45:67:89:00',), ]) def test_returns_failed_validation_on_invalid_mac_address(address): assert isinstance(mac_address(address), ValidationFailure) validators-0.20.0/tests/test_md5.py000066400000000000000000000010671424716171400172140ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest import validators @pytest.mark.parametrize('value', [ 'd41d8cd98f00b204e9800998ecf8427e', 'D41D8CD98F00B204E9800998ECF8427E' ]) def test_returns_true_on_valid_md5(value): assert validators.md5(value) @pytest.mark.parametrize('value', [ 'z41d8cd98f00b204e9800998ecf8427e', 'z8cd98f00b204e9800998ecf8427e', 'z4aaaa1d8cd98f00b204e9800998ecf8427e' ]) def test_returns_failed_validation_on_invalid_md5(value): result = validators.md5(value) assert isinstance(result, validators.ValidationFailure) validators-0.20.0/tests/test_sha1.py000066400000000000000000000011421424716171400173550ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest import validators @pytest.mark.parametrize('value', [ 'da39a3ee5e6b4b0d3255bfef95601890afd80709', 'DA39A3EE5E6B4B0D3255BFEF95601890AFD80709' ]) def test_returns_true_on_valid_sha1(value): assert validators.sha1(value) @pytest.mark.parametrize('value', [ 'za39a3ee5e6b4b0d3255bfef95601890afd80709', 'da39e5e6b4b0d3255bfef95601890afd80709', 'daaaa39a3ee5e6b4b0d3255bfef95601890afd80709' ]) def test_returns_failed_validation_on_invalid_sha1(value): result = validators.sha1(value) assert isinstance(result, validators.ValidationFailure) validators-0.20.0/tests/test_sha224.py000066400000000000000000000012721424716171400175300ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest import validators @pytest.mark.parametrize('value', [ 'd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f', 'D14A028C2A3A2BC9476102BB288234C415A2B01F828EA62AC5B3E42F' ]) def test_returns_true_on_valid_sha224(value): assert validators.sha224(value) @pytest.mark.parametrize('value', [ 'z14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f', 'd028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f', 'daaa14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f' ]) def test_returns_failed_validation_on_invalid_sha224(value): result = validators.sha224(value) assert isinstance(result, validators.ValidationFailure) validators-0.20.0/tests/test_sha256.py000066400000000000000000000013441424716171400175350ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest import validators @pytest.mark.parametrize('value', [ 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', 'E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855' ]) def test_returns_true_on_valid_sha256(value): assert validators.sha256(value) @pytest.mark.parametrize('value', [ 'z3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', 'ec44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', 'eaaaa3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', ]) def test_returns_failed_validation_on_invalid_sha256(value): result = validators.sha256(value) assert isinstance(result, validators.ValidationFailure) validators-0.20.0/tests/test_sha512.py000066400000000000000000000022521424716171400175270ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest import validators @pytest.mark.parametrize('value', [ ( 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d' '13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e' ), ( 'CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D' '13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E' ) ]) def test_returns_true_on_valid_sha512(value): assert validators.sha512(value) @pytest.mark.parametrize('value', [ ( 'zf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d' '13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e' ), ( 'cf8357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c' '5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e' ), ( 'cf8aaaa3e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce4' '7d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e' ) ]) def test_returns_failed_validation_on_invalid_sha512(value): result = validators.sha512(value) assert isinstance(result, validators.ValidationFailure) validators-0.20.0/tests/test_slug.py000066400000000000000000000007361424716171400175030ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import slug, ValidationFailure @pytest.mark.parametrize('value', [ '123-12312-asdasda', '123____123', 'dsadasd-dsadas', ]) def test_returns_true_on_valid_slug(value): assert slug(value) @pytest.mark.parametrize('value', [ 'some.slug', '1231321%', ' 21312', '123asda&', ]) def test_returns_failed_validation_on_invalid_slug(value): assert isinstance(slug(value), ValidationFailure) validators-0.20.0/tests/test_url.py000066400000000000000000000112341424716171400173260ustar00rootroot00000000000000# -*- coding: utf-8 -*- import pytest from validators import url, ValidationFailure @pytest.mark.parametrize('address', [ u'http://foobar.dk', u'http://foobar.museum/foobar', u'http://fo.com', u'http://FOO.com', u'http://foo.com/blah_blah', u'http://foo.com/blah_blah/', u'http://foo.com/blah_blah_(wikipedia)', u'http://foo.com/blah_blah_(wikipedia)_(again)', u'http://www.example.com/wpstyle/?p=364', u'https://www.example.com/foo/?bar=baz&inga=42&quux', u'https://www.example.com?bar=baz', u'http://✪df.ws/123', u'http://userid:password@example.com:8080', u'http://userid:password@example.com:8080/', u'http://userid@example.com', u'http://userid@example.com/', u'http://userid@example.com:8080', u'http://userid@example.com:8080/', u'http://userid:password@example.com', u'http://userid:password@example.com/', u'http://142.42.1.1/', u'http://142.42.1.1:8080/', u'http://➡.ws/䨹', u'http://⌘.ws', u'http://⌘.ws/', u'http://foo.com/blah_(wikipedia)#cite-1', u'http://foo.com/blah_(wikipedia)_blah#cite-1', u'http://foo.com/unicode_(✪)_in_parens', u'http://foo.com/(something)?after=parens', u'http://☺.damowmow.com/', u'http://code.google.com/events/#&product=browser', u'http://j.mp', u'ftp://foo.bar/baz', u'http://foo.bar/?q=Test%20URL-encoded%20stuff', u'http://مثال.إختبار', u'http://例子.测试', u'http://उदाहरण.परीक्षा', u'http://www.😉.com', u'http://😉.com/😁', u'http://উদাহরণ.বাংলা', u'http://xn--d5b6ci4b4b3a.xn--54b7fta0cc', u'http://дом-м.рф/1/asdf', u'http://xn----gtbybh.xn--p1ai/1/asdf', u'http://-.~_!$&\'()*+,;=:%40:80%2f::::::@example.com', u'http://1337.net', u'http://a.b-c.de', u'http://223.255.255.254', u'http://10.1.1.0', u'http://10.1.1.1', u'http://10.1.1.254', u'http://10.1.1.255', u'http://127.0.0.1:8080', u'http://127.0.10.150', u'http://localhost', u'http://localhost:8000', u'http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html', u'http://[1080:0:0:0:8:800:200C:417A]/index.html', u'http://[3ffe:2a00:100:7031::1]', u'http://[1080::8:800:200C:417A]/foo', u'http://[::192.9.5.5]/ipng', u'http://[::FFFF:129.144.52.38]:80/index.html', u'http://[2010:836B:4179::836B:4179]', ]) def test_returns_true_on_valid_url(address): assert url(address) @pytest.mark.parametrize('address, public', [ (u'http://foo.bar', True), (u'http://username:password@example.com:4010/', False), (u'http://username:password@112.168.10.10:4010/', True), (u'http://username:password@192.168.10.10:4010/', False), (u'http://10.0.10.1', False), (u'http://127.0.0.1', False), ]) def test_returns_true_on_valid_public_url(address, public): assert url(address, public=public) @pytest.mark.parametrize('address', [ 'http://foobar', 'foobar.dk', 'http://127.0.0/asdf', 'http://foobar.d', 'http://foobar.12', 'http://foobar', 'htp://foobar.com', 'http://foobar..com', 'http://fo..com', 'http://', 'http://.', 'http://..', 'http://../', 'http://?', 'http://??', 'http://??/', 'http://#', 'http://##', 'http://##/', 'http://foo.bar?q=Spaces should be encoded', '//', '//a', '///a', '///', 'http:///a', 'foo.com', 'rdar://1234', 'h://test', 'http:// shouldfail.com', ':// should fail', 'http://foo.bar/foo(bar)baz quux', 'ftps://foo.bar/', 'http://-error-.invalid/', 'http://a.b--c.de/', 'http://-a.b.co', 'http://a.b-.co', 'http://0.0.0.0', 'http://224.1.1.1', 'http://1.1.1.1.1', 'http://123.123.123', 'http://3628126748', 'http://.www.foo.bar/', 'http://www.foo.bar./', 'http://.www.foo.bar./', 'http://127.12.0.260', 'http://example.com/">user@example.com', 'http://[2010:836B:4179::836B:4179', 'http://2010:836B:4179::836B:4179', 'http://2010:836B:4179::836B:4179:80/index.html', ]) def test_returns_failed_validation_on_invalid_url(address): assert isinstance(url(address), ValidationFailure) @pytest.mark.parametrize('address, public', [ (u'http://username:password@192.168.10.10:4010/', True), (u'http://10.0.10.1', True), (u'http://127.0.0.1', True), (u'foo://127.0.0.1', True), (u'http://username:password@127.0.0.1:8080', True), (u'http://localhost', True), (u'http://localhost:8000', True), ]) def test_returns_failed_validation_on_invalid_public_url(address, public): assert isinstance(url(address, public=public), ValidationFailure) validators-0.20.0/tests/test_uuid.py000066400000000000000000000017511424716171400174750ustar00rootroot00000000000000# -*- coding: utf-8 -*- from uuid import UUID import pytest from validators import uuid, ValidationFailure @pytest.mark.parametrize(('value',), [ ('2bc1c94f-0deb-43e9-92a1-4775189ec9f8',), ]) def test_returns_true_on_valid_mac_address(value): assert uuid(value) @pytest.mark.parametrize(('value',), [ (UUID('2bc1c94f-0deb-43e9-92a1-4775189ec9f8'),), ]) def test_returns_true_on_valid_uuid_object(value): assert uuid(value) @pytest.mark.parametrize(('value',), [ ('2bc1c94f-deb-43e9-92a1-4775189ec9f8',), ('2bc1c94f-0deb-43e9-92a1-4775189ec9f',), ('gbc1c94f-0deb-43e9-92a1-4775189ec9f8',), ('2bc1c94f 0deb-43e9-92a1-4775189ec9f8',), ]) def test_returns_failed_validation_on_invalid_mac_address(value): assert isinstance(uuid(value), ValidationFailure) @pytest.mark.parametrize(('value',), [ (1,), (1.0,), (True,), (None,), ]) def test_returns_failed_validation_on_invalid_types(value): assert isinstance(uuid(value), ValidationFailure) validators-0.20.0/tests/test_validation_failure.py000066400000000000000000000011071424716171400223630ustar00rootroot00000000000000import validators obj_repr = ( "ValidationFailure(func=between" ) class TestValidationFailure(object): def setup_method(self, method): self.obj = validators.between(3, min=4, max=5) def test_boolean_coerce(self): assert not bool(self.obj) assert not self.obj def test_repr(self): assert obj_repr in repr(self.obj) def test_unicode(self): assert obj_repr in str(self.obj) def test_arguments_as_properties(self): assert self.obj.value == 3 assert self.obj.min == 4 assert self.obj.max == 5 validators-0.20.0/validators/000077500000000000000000000000001424716171400161205ustar00rootroot00000000000000validators-0.20.0/validators/__init__.py000066400000000000000000000021201424716171400202240ustar00rootroot00000000000000from .between import between from .btc_address import btc_address from .card import ( amex, card_number, diners, discover, jcb, mastercard, unionpay, visa ) from .domain import domain from .email import email from .extremes import Max, Min from .hashes import md5, sha1, sha224, sha256, sha512 from .i18n import fi_business_id, fi_ssn from .iban import iban from .ip_address import ipv4, ipv4_cidr, ipv6, ipv6_cidr from .length import length from .mac_address import mac_address from .slug import slug from .truthy import truthy from .url import url from .utils import ValidationFailure, validator from .uuid import uuid __all__ = ('between', 'domain', 'email', 'Max', 'Min', 'md5', 'sha1', 'sha224', 'sha256', 'sha512', 'fi_business_id', 'fi_ssn', 'iban', 'ipv4', 'ipv4_cidr', 'ipv6', 'ipv6_cidr', 'length', 'mac_address', 'slug', 'truthy', 'url', 'ValidationFailure', 'validator', 'uuid', 'card_number', 'visa', 'mastercard', 'amex', 'unionpay', 'diners', 'jcb', 'discover', 'btc_address') __version__ = '0.20.0' validators-0.20.0/validators/between.py000066400000000000000000000030501424716171400201210ustar00rootroot00000000000000from .extremes import Max, Min from .utils import validator @validator def between(value, min=None, max=None): """ Validate that a number is between minimum and/or maximum value. This will work with any comparable type, such as floats, decimals and dates not just integers. This validator is originally based on `WTForms NumberRange validator`_. .. _WTForms NumberRange validator: https://github.com/wtforms/wtforms/blob/master/wtforms/validators.py Examples:: >>> from datetime import datetime >>> between(5, min=2) True >>> between(13.2, min=13, max=14) True >>> between(500, max=400) ValidationFailure(func=between, args=...) >>> between( ... datetime(2000, 11, 11), ... min=datetime(1999, 11, 11) ... ) True :param min: The minimum required value of the number. If not provided, minimum value will not be checked. :param max: The maximum value of the number. If not provided, maximum value will not be checked. .. versionadded:: 0.2 """ if min is None and max is None: raise AssertionError( 'At least one of `min` or `max` must be specified.' ) if min is None: min = Min if max is None: max = Max try: min_gt_max = min > max except TypeError: min_gt_max = max < min if min_gt_max: raise AssertionError('`min` cannot be more than `max`.') return min <= value and max >= value validators-0.20.0/validators/btc_address.py000066400000000000000000000027721424716171400207570ustar00rootroot00000000000000import re from hashlib import sha256 from .utils import validator segwit_pattern = re.compile( r'^(bc|tc)[0-3][02-9ac-hj-np-z]{14,74}$') def validate_segwit_address(addr): return segwit_pattern.match(addr) def decode_base58(addr): alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" return sum([ (58 ** e) * alphabet.index(i) for e, i in enumerate(addr[::-1]) ]) def validate_old_btc_address(addr): "Validate P2PKH and P2SH type address" if not len(addr) in range(25, 35): return False decoded_bytes = decode_base58(addr).to_bytes(25, "big") header = decoded_bytes[:-4] checksum = decoded_bytes[-4:] return checksum == sha256(sha256(header).digest()).digest()[:4] @validator def btc_address(value): """ Return whether or not given value is a valid bitcoin address. If the value is valid bitcoin address this function returns ``True``, otherwise :class:`~validators.utils.ValidationFailure`. Full validation is implemented for P2PKH and P2SH addresses. For segwit addresses a regexp is used to provide a reasonable estimate on whether the address is valid. Examples:: >>> btc_address('3Cwgr2g7vsi1bXDUkpEnVoRLA9w4FZfC69') True :param value: Bitcoin address string to validate """ if not value or not isinstance(value, str): return False if value[:2] in ("bc", "tb"): return validate_segwit_address(value) return validate_old_btc_address(value) validators-0.20.0/validators/card.py000066400000000000000000000104371424716171400174100ustar00rootroot00000000000000import re from .utils import validator @validator def card_number(value): """ Return whether or not given value is a valid card number. This validator is based on Luhn algorithm. .. luhn: https://github.com/mmcloughlin/luhn Examples:: >>> card_number('4242424242424242') True >>> card_number('4242424242424241') ValidationFailure(func=card_number, args={'value': '4242424242424241'}) .. versionadded:: 0.15.0 :param value: card number string to validate """ try: digits = list(map(int, value)) odd_sum = sum(digits[-1::-2]) even_sum = sum([sum(divmod(2 * d, 10)) for d in digits[-2::-2]]) return (odd_sum + even_sum) % 10 == 0 except ValueError: return False @validator def visa(value): """ Return whether or not given value is a valid Visa card number. Examples:: >>> visa('4242424242424242') True >>> visa('2223003122003222') ValidationFailure(func=visa, args={'value': '2223003122003222'}) .. versionadded:: 0.15.0 :param value: Visa card number string to validate """ pattern = re.compile(r'^4') return card_number(value) and len(value) == 16 and pattern.match(value) @validator def mastercard(value): """ Return whether or not given value is a valid Mastercard card number. Examples:: >>> mastercard('5555555555554444') True >>> mastercard('4242424242424242') ValidationFailure(func=mastercard, args={'value': '4242424242424242'}) .. versionadded:: 0.15.0 :param value: Mastercard card number string to validate """ pattern = re.compile(r'^(51|52|53|54|55|22|23|24|25|26|27)') return card_number(value) and len(value) == 16 and pattern.match(value) @validator def amex(value): """ Return whether or not given value is a valid American Express card number. Examples:: >>> amex('378282246310005') True >>> amex('4242424242424242') ValidationFailure(func=amex, args={'value': '4242424242424242'}) .. versionadded:: 0.15.0 :param value: American Express card number string to validate """ pattern = re.compile(r'^(34|37)') return card_number(value) and len(value) == 15 and pattern.match(value) @validator def unionpay(value): """ Return whether or not given value is a valid UnionPay card number. Examples:: >>> unionpay('6200000000000005') True >>> unionpay('4242424242424242') ValidationFailure(func=unionpay, args={'value': '4242424242424242'}) .. versionadded:: 0.15.0 :param value: UnionPay card number string to validate """ pattern = re.compile(r'^62') return card_number(value) and len(value) == 16 and pattern.match(value) @validator def diners(value): """ Return whether or not given value is a valid Diners Club card number. Examples:: >>> diners('3056930009020004') True >>> diners('4242424242424242') ValidationFailure(func=diners, args={'value': '4242424242424242'}) .. versionadded:: 0.15.0 :param value: Diners Club card number string to validate """ pattern = re.compile(r'^(30|36|38|39)') return ( card_number(value) and len(value) in [14, 16] and pattern.match(value) ) @validator def jcb(value): """ Return whether or not given value is a valid JCB card number. Examples:: >>> jcb('3566002020360505') True >>> jcb('4242424242424242') ValidationFailure(func=jcb, args={'value': '4242424242424242'}) .. versionadded:: 0.15.0 :param value: JCB card number string to validate """ pattern = re.compile(r'^35') return card_number(value) and len(value) == 16 and pattern.match(value) @validator def discover(value): """ Return whether or not given value is a valid Discover card number. Examples:: >>> discover('6011111111111117') True >>> discover('4242424242424242') ValidationFailure(func=discover, args={'value': '4242424242424242'}) .. versionadded:: 0.15.0 :param value: Discover card number string to validate """ pattern = re.compile(r'^(60|64|65)') return card_number(value) and len(value) == 16 and pattern.match(value) validators-0.20.0/validators/domain.py000066400000000000000000000024451424716171400177460ustar00rootroot00000000000000import re from .utils import validator pattern = re.compile( r'^(?:[a-zA-Z0-9]' # First character of the domain r'(?:[a-zA-Z0-9-_]{0,61}[A-Za-z0-9])?\.)' # Sub domain + hostname r'+[A-Za-z0-9][A-Za-z0-9-_]{0,61}' # First 61 characters of the gTLD r'[A-Za-z]$' # Last character of the gTLD ) def to_unicode(obj, charset='utf-8', errors='strict'): if obj is None: return None if not isinstance(obj, bytes): return str(obj) return obj.decode(charset, errors) @validator def domain(value): """ Return whether or not given value is a valid domain. If the value is valid domain name this function returns ``True``, otherwise :class:`~validators.utils.ValidationFailure`. Examples:: >>> domain('example.com') True >>> domain('example.com/') ValidationFailure(func=domain, ...) Supports IDN domains as well:: >>> domain('xn----gtbspbbmkef.xn--p1ai') True .. versionadded:: 0.9 .. versionchanged:: 0.10 Added support for internationalized domain name (IDN) validation. :param value: domain string to validate """ try: return pattern.match(to_unicode(value).encode('idna').decode('ascii')) except (UnicodeError, AttributeError): return False validators-0.20.0/validators/email.py000066400000000000000000000036731424716171400175720ustar00rootroot00000000000000import re from .utils import validator user_regex = re.compile( # dot-atom r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+" r"(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*$" # quoted-string r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|' r"""\\[\001-\011\013\014\016-\177])*"$)""", re.IGNORECASE ) domain_regex = re.compile( # domain r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+' r'(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?$)' # literal form, ipv4 address (SMTP 4.1.3) r'|^\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)' r'(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) domain_whitelist = ['localhost'] @validator def email(value, whitelist=None): """ Validate an email address. This validator is based on `Django's email validator`_. Returns ``True`` on success and :class:`~validators.utils.ValidationFailure` when validation fails. Examples:: >>> email('someone@example.com') True >>> email('bogus@@') ValidationFailure(func=email, ...) .. _Django's email validator: https://github.com/django/django/blob/master/django/core/validators.py .. versionadded:: 0.1 :param value: value to validate :param whitelist: domain names to whitelist :copyright: (c) Django Software Foundation and individual contributors. :license: BSD """ if whitelist is None: whitelist = domain_whitelist if not value or '@' not in value: return False user_part, domain_part = value.rsplit('@', 1) if not user_regex.match(user_part): return False if len(user_part.encode("utf-8")) > 64: return False if domain_part not in whitelist and not domain_regex.match(domain_part): # Try for possible IDN domain-part try: domain_part = domain_part.encode('idna').decode('ascii') return domain_regex.match(domain_part) except UnicodeError: return False return True validators-0.20.0/validators/extremes.py000066400000000000000000000017371424716171400203360ustar00rootroot00000000000000from functools import total_ordering @total_ordering class Min(object): """ An object that is less than any other object (except itself). Inspired by https://pypi.python.org/pypi/Extremes Examples:: >>> import sys >>> Min < -sys.maxint True >>> Min < None True >>> Min < '' True .. versionadded:: 0.2 """ def __lt__(self, other): if other is Min: return False return True @total_ordering class Max(object): """ An object that is greater than any other object (except itself). Inspired by https://pypi.python.org/pypi/Extremes Examples:: >>> import sys >>> Max > Min True >>> Max > sys.maxint True >>> Max > 99999999999999999 True .. versionadded:: 0.2 """ def __gt__(self, other): if other is Max: return False return True Min = Min() Max = Max() validators-0.20.0/validators/hashes.py000066400000000000000000000047031424716171400177510ustar00rootroot00000000000000import re from .utils import validator md5_regex = re.compile( r"^[0-9a-f]{32}$", re.IGNORECASE ) sha1_regex = re.compile( r"^[0-9a-f]{40}$", re.IGNORECASE ) sha224_regex = re.compile( r"^[0-9a-f]{56}$", re.IGNORECASE ) sha256_regex = re.compile( r"^[0-9a-f]{64}$", re.IGNORECASE ) sha512_regex = re.compile( r"^[0-9a-f]{128}$", re.IGNORECASE ) @validator def md5(value): """ Return whether or not given value is a valid MD5 hash. Examples:: >>> md5('d41d8cd98f00b204e9800998ecf8427e') True >>> md5('900zz11') ValidationFailure(func=md5, args={'value': '900zz11'}) :param value: MD5 string to validate """ return md5_regex.match(value) @validator def sha1(value): """ Return whether or not given value is a valid SHA1 hash. Examples:: >>> sha1('da39a3ee5e6b4b0d3255bfef95601890afd80709') True >>> sha1('900zz11') ValidationFailure(func=sha1, args={'value': '900zz11'}) :param value: SHA1 string to validate """ return sha1_regex.match(value) @validator def sha224(value): """ Return whether or not given value is a valid SHA224 hash. Examples:: >>> sha224('d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f') True >>> sha224('900zz11') ValidationFailure(func=sha224, args={'value': '900zz11'}) :param value: SHA224 string to validate """ return sha224_regex.match(value) @validator def sha256(value): """ Return whether or not given value is a valid SHA256 hash. Examples:: >>> sha256( ... 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b' ... '855' ... ) True >>> sha256('900zz11') ValidationFailure(func=sha256, args={'value': '900zz11'}) :param value: SHA256 string to validate """ return sha256_regex.match(value) @validator def sha512(value): """ Return whether or not given value is a valid SHA512 hash. Examples:: >>> sha512( ... 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce' ... '9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af9' ... '27da3e' ... ) True >>> sha512('900zz11') ValidationFailure(func=sha512, args={'value': '900zz11'}) :param value: SHA512 string to validate """ return sha512_regex.match(value) validators-0.20.0/validators/i18n/000077500000000000000000000000001424716171400166775ustar00rootroot00000000000000validators-0.20.0/validators/i18n/__init__.py000066400000000000000000000002251424716171400210070ustar00rootroot00000000000000# TODO: remove, let the user import it if they really want it from .fi import fi_business_id, fi_ssn # noqa __all__ = ('fi_business_id', 'fi_ssn') validators-0.20.0/validators/i18n/es.py000066400000000000000000000116301424716171400176610ustar00rootroot00000000000000# -*- coding: utf-8 -*- from validators.utils import validator __all__ = ('es_cif', 'es_nif', 'es_nie', 'es_doi',) def nif_nie_validation(doi, number_by_letter, special_cases): """ Validate if the doi is a NIF or a NIE. :param doi: DOI to validate. :return: boolean if it's valid. """ doi = doi.upper() if doi in special_cases: return False table = 'TRWAGMYFPDXBNJZSQVHLCKE' if len(doi) != 9: return False control = doi[8] # If it is not a DNI, convert the first letter to the corresponding # digit numbers = number_by_letter.get(doi[0], doi[0]) + doi[1:8] return numbers.isdigit() and control == table[int(numbers) % 23] @validator def es_cif(doi): """ Validate a Spanish CIF. Each company in Spain prior to 2008 had a distinct CIF and has been discontinued. For more information see `wikipedia.org/cif`_. The new replacement is to use NIF for absolutely everything. The issue is that there are "types" of NIFs now: company, person[citizen vs recident] all distinguished by the first character of the DOI. For this reason we will continue to call CIF NIFs that are used for companies. This validator is based on `generadordni.es`_. .. _generadordni.es: https://generadordni.es/ .. _wikipedia.org/cif: https://es.wikipedia.org/wiki/C%C3%B3digo_de_identificaci%C3%B3n_fiscal Examples:: >>> es_cif('B25162520') True >>> es_cif('B25162529') ValidationFailure(func=es_cif, args=...) .. versionadded:: 0.13.0 :param doi: DOI to validate """ doi = doi.upper() if len(doi) != 9: return False table = 'JABCDEFGHI' first_chr = doi[0] doi_body = doi[1:8] control = doi[8] if not doi_body.isdigit(): return False odd_result = 0 even_result = 0 for index, char in enumerate(doi_body): if index % 2 == 0: # Multiply each each odd position doi digit by 2 and sum it all # together odd_result += sum(map(int, str(int(char) * 2))) else: even_result += int(char) res = (10 - (even_result + odd_result) % 10) % 10 if first_chr in 'ABEH': # Number type return str(res) == control elif first_chr in 'PSQW': # Letter type return table[res] == control elif first_chr not in 'CDFGJNRUV': return False return control == str(res) or control == table[res] @validator def es_nif(doi): """ Validate a Spanish NIF. Each entity, be it person or company in Spain has a distinct NIF. Since we've designated CIF to be a company NIF, this NIF is only for person. For more information see `wikipedia.org/nif`_. This validator is based on `generadordni.es`_. .. _generadordni.es: https://generadordni.es/ .. _wikipedia.org/nif: https://es.wikipedia.org/wiki/N%C3%BAmero_de_identificaci%C3%B3n_fiscal Examples:: >>> es_nif('26643189N') True >>> es_nif('26643189X') ValidationFailure(func=es_nif, args=...) .. versionadded:: 0.13.0 :param doi: DOI to validate """ number_by_letter = {'L': '0', 'M': '0', 'K': '0'} special_cases = ['X0000000T', '00000000T', '00000001R'] return nif_nie_validation(doi, number_by_letter, special_cases) @validator def es_nie(doi): """ Validate a Spanish NIE. The NIE is a tax identification number in Spain, known in Spanish as the NIE, or more formally the Número de identidad de extranjero. For more information see `wikipedia.org/nie`_. This validator is based on `generadordni.es`_. .. _generadordni.es: https://generadordni.es/ .. _wikipedia.org/nie: https://es.wikipedia.org/wiki/N%C3%BAmero_de_identidad_de_extranjero Examples:: >>> es_nie('X0095892M') True >>> es_nie('X0095892X') ValidationFailure(func=es_nie, args=...) .. versionadded:: 0.13.0 :param doi: DOI to validate """ number_by_letter = {'X': '0', 'Y': '1', 'Z': '2'} special_cases = ['X0000000T'] # NIE must must start with X Y or Z if not doi or doi[0] not in number_by_letter.keys(): return False return nif_nie_validation(doi, number_by_letter, special_cases) @validator def es_doi(doi): """ Validate a Spanish DOI. A DOI in spain is all NIF / CIF / NIE / DNI -- a digital ID. For more information see `wikipedia.org/doi`_. This validator is based on `generadordni.es`_. .. _generadordni.es: https://generadordni.es/ .. _wikipedia.org/doi: https://es.wikipedia.org/wiki/Identificador_de_objeto_digital Examples:: >>> es_doi('X0095892M') True >>> es_doi('X0095892X') ValidationFailure(func=es_doi, args=...) .. versionadded:: 0.13.0 :param doi: DOI to validate """ return es_nie(doi) or es_nif(doi) or es_cif(doi) validators-0.20.0/validators/i18n/fi.py000066400000000000000000000047271424716171400176610ustar00rootroot00000000000000import re from validators.utils import validator business_id_pattern = re.compile(r'^[0-9]{7}-[0-9]$') ssn_checkmarks = '0123456789ABCDEFHJKLMNPRSTUVWXY' ssn_pattern = re.compile( r"""^ (?P(0[1-9]|[1-2]\d|3[01]) (0[1-9]|1[012]) (\d{{2}})) [A+-] (?P(\d{{3}})) (?P[{checkmarks}])$""".format(checkmarks=ssn_checkmarks), re.VERBOSE ) @validator def fi_business_id(business_id): """ Validate a Finnish Business ID. Each company in Finland has a distinct business id. For more information see `Finnish Trade Register`_ .. _Finnish Trade Register: http://en.wikipedia.org/wiki/Finnish_Trade_Register Examples:: >>> fi_business_id('0112038-9') # Fast Monkeys Ltd True >>> fi_business_id('1234567-8') # Bogus ID ValidationFailure(func=fi_business_id, ...) .. versionadded:: 0.4 .. versionchanged:: 0.5 Method renamed from ``finnish_business_id`` to ``fi_business_id`` :param business_id: business_id to validate """ if not business_id or not re.match(business_id_pattern, business_id): return False factors = [7, 9, 10, 5, 8, 4, 2] numbers = map(int, business_id[:7]) checksum = int(business_id[8]) sum_ = sum(f * n for f, n in zip(factors, numbers)) modulo = sum_ % 11 return (11 - modulo == checksum) or (modulo == 0 and checksum == 0) @validator def fi_ssn(ssn, allow_temporal_ssn=True): """ Validate a Finnish Social Security Number. This validator is based on `django-localflavor-fi`_. .. _django-localflavor-fi: https://github.com/django/django-localflavor-fi/ Examples:: >>> fi_ssn('010101-0101') True >>> fi_ssn('101010-0102') ValidationFailure(func=fi_ssn, args=...) .. versionadded:: 0.5 :param ssn: Social Security Number to validate :param allow_temporal_ssn: Whether to accept temporal SSN numbers. Temporal SSN numbers are the ones where the serial is in the range [900-999]. By default temporal SSN numbers are valid. """ if not ssn: return False result = re.match(ssn_pattern, ssn) if not result: return False gd = result.groupdict() checksum = int(gd['date'] + gd['serial']) return ( int(gd['serial']) >= 2 and (allow_temporal_ssn or int(gd['serial']) <= 899) and ssn_checkmarks[checksum % len(ssn_checkmarks)] == gd['checksum'] ) validators-0.20.0/validators/iban.py000066400000000000000000000022171424716171400174050ustar00rootroot00000000000000import re from .utils import validator regex = ( r'^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$' ) pattern = re.compile(regex) def char_value(char): """A=10, B=11, ..., Z=35 """ if char.isdigit(): return int(char) else: return 10 + ord(char) - ord('A') def modcheck(value): """Check if the value string passes the mod97-test. """ # move country code and check numbers to end rearranged = value[4:] + value[:4] # convert letters to numbers converted = [char_value(char) for char in rearranged] # interpret as integer integerized = int(''.join([str(i) for i in converted])) return (integerized % 97 == 1) @validator def iban(value): """ Return whether or not given value is a valid IBAN code. If the value is a valid IBAN this function returns ``True``, otherwise :class:`~validators.utils.ValidationFailure`. Examples:: >>> iban('DE29100500001061045672') True >>> iban('123456') ValidationFailure(func=iban, ...) .. versionadded:: 0.8 :param value: IBAN string to validate """ return pattern.match(value) and modcheck(value) validators-0.20.0/validators/ip_address.py000066400000000000000000000077661424716171400206270ustar00rootroot00000000000000from .utils import validator @validator def ipv4(value): """ Return whether a given value is a valid IP version 4 address. This validator is based on `WTForms IPAddress validator`_ .. _WTForms IPAddress validator: https://github.com/wtforms/wtforms/blob/master/wtforms/validators.py Examples:: >>> ipv4('123.0.0.7') True >>> ipv4('900.80.70.11') ValidationFailure(func=ipv4, args={'value': '900.80.70.11'}) .. versionadded:: 0.2 :param value: IP address string to validate """ groups = value.split(".") if ( len(groups) != 4 or any(not x.isdigit() for x in groups) or any(len(x) > 3 for x in groups) ): return False return all(0 <= int(part) < 256 for part in groups) @validator def ipv4_cidr(value): """ Return whether a given value is a valid CIDR-notated IP version 4 address range. This validator is based on RFC4632 3.1. Examples:: >>> ipv4_cidr('1.1.1.1/8') True >>> ipv4_cidr('1.1.1.1') ValidationFailure(func=ipv4_cidr, args={'value': '1.1.1.1'}) """ try: prefix, suffix = value.split('/', 2) except ValueError: return False if not ipv4(prefix) or not suffix.isdigit(): return False return 0 <= int(suffix) <= 32 @validator def ipv6(value): """ Return whether a given value is a valid IP version 6 address (including IPv4-mapped IPv6 addresses). This validator is based on `WTForms IPAddress validator`_. .. _WTForms IPAddress validator: https://github.com/wtforms/wtforms/blob/master/wtforms/validators.py Examples:: >>> ipv6('abcd:ef::42:1') True >>> ipv6('::ffff:192.0.2.128') True >>> ipv6('::192.0.2.128') True >>> ipv6('abc.0.0.1') ValidationFailure(func=ipv6, args={'value': 'abc.0.0.1'}) .. versionadded:: 0.2 :param value: IP address string to validate """ ipv6_groups = value.split(':') if len(ipv6_groups) == 1: return False ipv4_groups = ipv6_groups[-1].split('.') if len(ipv4_groups) > 1: if not ipv4(ipv6_groups[-1]): return False ipv6_groups = ipv6_groups[:-1] else: ipv4_groups = [] count_blank = 0 for part in ipv6_groups: if not part: count_blank += 1 continue try: num = int(part, 16) except ValueError: return False else: if not 0 <= num <= 65536 or len(part) > 4: return False max_groups = 6 if ipv4_groups else 8 part_count = len(ipv6_groups) - count_blank if count_blank == 0 and part_count == max_groups: # no :: -> must have size of max_groups return True elif count_blank == 1 and ipv6_groups[-1] and ipv6_groups[0] and part_count < max_groups: # one :: inside the address or prefix or suffix : -> filter least two cases return True elif count_blank == 2 and part_count < max_groups and ( ((ipv6_groups[0] and not ipv6_groups[-1]) or (not ipv6_groups[0] and ipv6_groups[-1])) or ipv4_groups): # leading or trailing :: or : at end and begin -> filter last case # Check if it has ipv4 groups because they get removed from the ipv6_groups return True elif count_blank == 3 and part_count == 0: # :: is the address -> filter everything else return True return False @validator def ipv6_cidr(value): """ Returns whether a given value is a valid CIDR-notated IP version 6 address range. This validator is based on RFC4632 3.1. Examples:: >>> ipv6_cidr('::1/128') True >>> ipv6_cidr('::1') ValidationFailure(func=ipv6_cidr, args={'value': '::1'}) """ try: prefix, suffix = value.split('/', 2) except ValueError: return False if not ipv6(prefix) or not suffix.isdigit(): return False return 0 <= int(suffix) <= 128 validators-0.20.0/validators/length.py000066400000000000000000000017121424716171400177540ustar00rootroot00000000000000from .between import between from .utils import validator @validator def length(value, min=None, max=None): """ Return whether or not the length of given string is within a specified range. Examples:: >>> length('something', min=2) True >>> length('something', min=9, max=9) True >>> length('something', max=5) ValidationFailure(func=length, ...) :param value: The string to validate. :param min: The minimum required length of the string. If not provided, minimum length will not be checked. :param max: The maximum length of the string. If not provided, maximum length will not be checked. .. versionadded:: 0.2 """ if (min is not None and min < 0) or (max is not None and max < 0): raise AssertionError( '`min` and `max` need to be greater than zero.' ) return between(len(value), min=min, max=max) validators-0.20.0/validators/mac_address.py000066400000000000000000000015041424716171400207370ustar00rootroot00000000000000import re from .utils import validator pattern = re.compile(r'^(?:[0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$') @validator def mac_address(value): """ Return whether or not given value is a valid MAC address. If the value is valid MAC address this function returns ``True``, otherwise :class:`~validators.utils.ValidationFailure`. This validator is based on `WTForms MacAddress validator`_. .. _WTForms MacAddress validator: https://github.com/wtforms/wtforms/blob/master/wtforms/validators.py Examples:: >>> mac_address('01:23:45:67:ab:CD') True >>> mac_address('00:00:00:00:00') ValidationFailure(func=mac_address, args={'value': '00:00:00:00:00'}) .. versionadded:: 0.2 :param value: Mac address string to validate """ return pattern.match(value) validators-0.20.0/validators/slug.py000066400000000000000000000010211424716171400174360ustar00rootroot00000000000000import re from .utils import validator slug_regex = re.compile(r'^[-a-zA-Z0-9_]+$') @validator def slug(value): """ Validate whether or not given value is valid slug. Valid slug can contain only alphanumeric characters, hyphens and underscores. Examples:: >>> slug('my.slug') ValidationFailure(func=slug, args={'value': 'my.slug'}) >>> slug('my-slug-2134') True .. versionadded:: 0.6 :param value: value to validate """ return slug_regex.match(value) validators-0.20.0/validators/truthy.py000066400000000000000000000015541424716171400200360ustar00rootroot00000000000000from .utils import validator @validator def truthy(value): """ Validate that given value is not a falsey value. This validator is based on `WTForms DataRequired validator`_. .. _WTForms DataRequired validator: https://github.com/wtforms/wtforms/blob/master/wtforms/validators.py Examples:: >>> truthy(1) True >>> truthy('someone') True >>> truthy(0) ValidationFailure(func=truthy, args={'value': 0}) >>> truthy(' ') ValidationFailure(func=truthy, args={'value': ' '}) >>> truthy(False) ValidationFailure(func=truthy, args={'value': False}) >>> truthy(None) ValidationFailure(func=truthy, args={'value': None}) .. versionadded:: 0.2 """ return ( value and (not isinstance(value, str) or value.strip()) ) validators-0.20.0/validators/url.py000066400000000000000000000115111424716171400172730ustar00rootroot00000000000000import re from .utils import validator ip_middle_octet = r"(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5]))" ip_last_octet = r"(?:\.(?:0|[1-9]\d?|1\d\d|2[0-4]\d|25[0-5]))" regex = re.compile( # noqa: W605 r"^" # protocol identifier r"(?:(?:https?|ftp)://)" # user:pass authentication r"(?:[-a-z\u00a1-\uffff0-9._~%!$&'()*+,;=:]+" r"(?::[-a-z0-9._~%!$&'()*+,;=:]*)?@)?" r"(?:" r"(?P" # IP address exclusion # private & local networks r"(?:(?:10|127)" + ip_middle_octet + r"{2}" + ip_last_octet + r")|" r"(?:(?:169\.254|192\.168)" + ip_middle_octet + ip_last_octet + r")|" r"(?:172\.(?:1[6-9]|2\d|3[0-1])" + ip_middle_octet + ip_last_octet + r"))" r"|" # private & local hosts r"(?P" r"(?:localhost))" r"|" # IP address dotted notation octets # excludes loopback network 0.0.0.0 # excludes reserved space >= 224.0.0.0 # excludes network & broadcast addresses # (first & last IP address of each class) r"(?P" r"(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])" r"" + ip_middle_octet + r"{2}" r"" + ip_last_octet + r")" r"|" # IPv6 RegEx from https://stackoverflow.com/a/17871737 r"\[(" # 1:2:3:4:5:6:7:8 r"([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" # 1:: 1:2:3:4:5:6:7:: r"([0-9a-fA-F]{1,4}:){1,7}:|" # 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 r"([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 r"([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 r"([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 r"([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 r"([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 r"[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: r":((:[0-9a-fA-F]{1,4}){1,7}|:)|" # fe80::7:8%eth0 fe80::7:8%1 # (link-local IPv6 addresses with zone index) r"fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|" r"::(ffff(:0{1,4}){0,1}:){0,1}" r"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}" # ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 # (IPv4-mapped IPv6 addresses and IPv4-translated addresses) r"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|" r"([0-9a-fA-F]{1,4}:){1,4}:" r"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}" # 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 # (IPv4-Embedded IPv6 Address) r"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])" r")\]|" # host name r"(?:(?:(?:xn--[-]{0,2})|[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]-?)*" r"[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]+)" # domain name r"(?:\.(?:(?:xn--[-]{0,2})|[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]-?)*" r"[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]+)*" # TLD identifier r"(?:\.(?:(?:xn--[-]{0,2}[a-z\u00a1-\uffff\U00010000-\U0010ffff0-9]{2,})|" r"[a-z\u00a1-\uffff\U00010000-\U0010ffff]{2,}))" r")" # port number r"(?::\d{2,5})?" # resource path r"(?:/[-a-z\u00a1-\uffff\U00010000-\U0010ffff0-9._~%!$&'()*+,;=:@/]*)?" # query string r"(?:\?\S*)?" # fragment r"(?:#\S*)?" r"$", re.UNICODE | re.IGNORECASE ) pattern = re.compile(regex) @validator def url(value, public=False): """ Return whether or not given value is a valid URL. If the value is valid URL this function returns ``True``, otherwise :class:`~validators.utils.ValidationFailure`. This validator is based on the wonderful `URL validator of dperini`_. .. _URL validator of dperini: https://gist.github.com/dperini/729294 Examples:: >>> url('http://foobar.dk') True >>> url('ftp://foobar.dk') True >>> url('http://10.0.0.1') True >>> url('http://foobar.d') ValidationFailure(func=url, ...) >>> url('http://10.0.0.1', public=True) ValidationFailure(func=url, ...) .. versionadded:: 0.2 .. versionchanged:: 0.10.2 Added support for various exotic URLs and fixed various false positives. .. versionchanged:: 0.10.3 Added ``public`` parameter. .. versionchanged:: 0.11.0 Made the regular expression this function uses case insensitive. .. versionchanged:: 0.11.3 Added support for URLs containing localhost :param value: URL address string to validate :param public: (default=False) Set True to only allow a public IP address """ result = pattern.match(value) if not public: return result return result and not any( (result.groupdict().get(key) for key in ('private_ip', 'private_host')) ) validators-0.20.0/validators/utils.py000066400000000000000000000037461424716171400176440ustar00rootroot00000000000000import inspect import itertools from collections import OrderedDict from decorator import decorator class ValidationFailure(Exception): def __init__(self, func, args): self.func = func self.__dict__.update(args) def __repr__(self): return u'ValidationFailure(func={func}, args={args})'.format( func=self.func.__name__, args=dict( [(k, v) for (k, v) in self.__dict__.items() if k != 'func'] ) ) def __str__(self): return repr(self) def __unicode__(self): return repr(self) def __bool__(self): return False def __nonzero__(self): return False def func_args_as_dict(func, args, kwargs): """ Return given function's positional and key value arguments as an ordered dictionary. """ _getargspec = inspect.getfullargspec arg_names = list( OrderedDict.fromkeys( itertools.chain( _getargspec(func)[0], kwargs.keys() ) ) ) return OrderedDict( list(zip(arg_names, args)) + list(kwargs.items()) ) def validator(func, *args, **kwargs): """ A decorator that makes given function validator. Whenever the given function is called and returns ``False`` value this decorator returns :class:`ValidationFailure` object. Example:: >>> @validator ... def even(value): ... return not (value % 2) >>> even(4) True >>> even(5) ValidationFailure(func=even, args={'value': 5}) :param func: function to decorate :param args: positional function arguments :param kwargs: key value function arguments """ def wrapper(func, *args, **kwargs): value = func(*args, **kwargs) if not value: return ValidationFailure( func, func_args_as_dict(func, args, kwargs) ) return True return decorator(wrapper, func) validators-0.20.0/validators/uuid.py000066400000000000000000000017121424716171400174410ustar00rootroot00000000000000from __future__ import absolute_import import re from uuid import UUID from .utils import validator pattern = re.compile(r'^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') @validator def uuid(value): """ Return whether or not given value is a valid UUID. If the value is valid UUID this function returns ``True``, otherwise :class:`~validators.utils.ValidationFailure`. This validator is based on `WTForms UUID validator`_. .. _WTForms UUID validator: https://github.com/wtforms/wtforms/blob/master/wtforms/validators.py Examples:: >>> uuid('2bc1c94f-0deb-43e9-92a1-4775189ec9f8') True >>> uuid('2bc1c94f 0deb-43e9-92a1-4775189ec9f8') ValidationFailure(func=uuid, ...) .. versionadded:: 0.2 :param value: UUID value to validate """ if isinstance(value, UUID): return True try: return pattern.match(value) except TypeError: return False