Metadata-Version: 1.1
Name: formv
Version: 0.0.2
Summary: HTML forms data validation, conversion & transformation
Home-page: UNKNOWN
Author: Adrian Cristea
Author-email: adrian.cristea@gmail.com 
License: MIT
Description: *formv* is a configurable Python library that can be used to validate, 
        convert & transform HTML forms data.
         
        Tested under Python 2.7 and 3.2.
        
        Includes validators for::
        
          - basic types 
              boolean, strings, numbers, dates, time, ranges, lists, sets
          - chained types 
              pairs, multiple fields, post-codes, states, currencies, 
              languages, phone numbers, credit cards
          - compound types 
              any validator, piped validators
          - signers & encoders 
              cost-based PBKDF2 encoding used to sign strings (e.g. cookies), 
              encode strings (e.g. user, password) and sign serialized objects 
              (e.g. serialized sessions stored on disk)  
          - documents (.pdf, .txt, .csv, .doc, etc.)
              can be validated (size, mime-type), stored, backed-up, compressed, reused
          - images (.jpg, .png, .gif, etc.)
              can be validated (size, mime-type), stored, backed-up, resized, watermarked, 
              imprinted, reused
          - geographic data 
              based on extendable YAML configuration files or user-defined callables: 
              countries, country-codes, states, various naming styles, currencies, 
              languages, post-codes, latitude, longitude, geo-distance calculation
          - network related 
              IPv4, IPv6, CIDR, MAC
          - web-forms (schema validation)
              simple fields, chained fields, key-based dependency
                
        Example:: 
        
            # schema validation including file upload, file transformation and file recovery 
            #---------------------------------------------------------------------------------
            
            import os, formv
            from formv.configuration import build
            from formv.validators import *
            from formv.exception import Invalid
            
            from formv.utils import dict_object
            from formv.utils.compat import PY2
            from formv.utils.fileinfo import BaseFileInfo, ReusedFileInfo 
            
            from tests import multipart
            from examples import to_str, make_environ as env
            
            from datetime import datetime
            from mimetypes import guess_type
            from webob import Request, Response
        
            app_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        
            # configuration is required only if you use validators based on 
            # geographic data: countries, currencies, languages, post-codes, 
            # latitude, longitude, geo-distance calculation,...
        
            formv.config = build(config_root=os.path.join(app_root, 'tests'))
            
            session = dict_object(files=dict_object())
             
            class WebForm(VSchema):
                fields = {         
                    'first_name': VString(min_len=3, max_len=50), 
                    'last_name': VString(min_len=3, max_len=50), 
                    'postcode': VString(), 
                    'state': VString(),
                    'country': VCountry(required=True, mode='by-name'), 
                    'email': VEmail(required=True), 
                    'password': VPassword(special_chars=3),
                    'file_upload': VPipe(VUploadFile(), 
                                         VWatermarkImage(type='image', 
                                                         file=os.path.join(app_root, 
                                                                           'tests/watermarks/copyright.jpg'), 
                                                         opacity=.04, angle=45), 
                                         VWatermarkImage(text='formv text watermark', angle=25, 
                                                         color=(0,0,0,128), opacity=1), 
                                         VImprintImage(text='Note the image watermark in the background',  
                                                       color=(0,128,128,255)), 
                                         VImprintImage(text=datetime.strftime(datetime.utcnow(),  
                                                                              'Uploaded on %Y/%m/%d - %H:%M:%S GMT'), 
                                                       color=(255,128,128,255), 
                                                       margin=(25,10)), 
                                   ) 
                } 
            
                chains = { 
                    'coordinates': VCountryPostcode(country_field='country',     # extracts (latitude, longitude) pair
                                                    postcode_field='postcode'),         
                    'password': VEncodedPair(required_field='password',          # encodes (password, email) pair
                                             required_label='Password', 
                                             available_field='email'),
                    'state': VState(country_field='country',                     # validates state against country
                                    state_field='state', mode='by-name'),
                } 
                 
            class Application(object):
                def __call__(self, environ, start_response):
                    self.request = Request(make_environ())  
                    response = self.request.get_response(self.response())
                    return response(self.request.environ, start_response)
                
                def response(self):
                    try:
                        form = self.validate(self.request.POST) # - form validation
                        body = to_str(form)
                    except Invalid as e:
                        # - recover successfully uploaded files 
                        if isinstance(e.value.get('file_upload'), BaseFileInfo): 
                            session.files['file_upload'] = ReusedFileInfo(e.value['file_upload']) 
                                            
                        body = e.message
                        body += '<br/>errors'
                        body += to_str(e.errors)
                        body += '<br/>values'
                        body += to_str(e.value)
            
                    response = Response()                        
                    response.text = unicode(body) if PY2 else body
                    return response
                    
                def validate(self, request): 
                    form = WebForm(allow_missing_keys=True, 
                                   allow_extra_keys=True, 
                                   replace_empty_value=True, 
                                   empty_values={ 
                                       # injects recovered file back into form if no new file has been uploaded 
                                       'file_upload': session.files.get('file_upload'), 
                                   }) 
                    return form.validate(request) 
                        
            application = Application()  
                 
            def make_environ():
                ''' simulates a POST request (multipart/form-data) '''
                
                app_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
                test_files_dir = os.path.join(app_root, 'tests/files')    
                form = []
            
                # - plain fields
                form.append(multipart.field('first_name', 'John'))
                form.append(multipart.field('last_name', 'Smith'))
                form.append(multipart.field('email', 'dummy@dummy.com'))
                form.append(multipart.field('postcode', '99501'))
                form.append(multipart.field('state', 'Alaska'))
                form.append(multipart.field('country', 'U.S.A.'))
                form.append(multipart.field('password', 'dummy-secret-password-1'))
                
                # - upload fields
                f = os.path.join(test_files_dir, 'test.jpg')
                form.append(multipart.file('file_upload', filename=f, 
                                           content_type=guess_type(f, False)[0]))            
                return env(*form)
            
            
            if __name__ == '__main__':
                from wsgiref.simple_server import make_server   
                httpd = make_server('127.0.0.1', 9000, application)
                sn = httpd.socket.getsockname()
                print("Serving HTTP on", sn[0], "port", sn[1], "...")            
                httpd.serve_forever()
             
        Output::
        
            +----------------------------------------------------------------------------------------------------------+
            | Field Name  | Field Value                                                                                |
            +==========================================================================================================+
            | coordinates | (61.216799, -149.87828)                                                                    |
            +----------------------------------------------------------------------------------------------------------+
            | country     | 'USA'                                                                                      |
            +----------------------------------------------------------------------------------------------------------+
            | email       | 'dummy@dummy.com'                                                                          |
            +----------------------------------------------------------------------------------------------------------+
            | file_upload | dir_path = '/srv/www/public'                                                               |
            |             | file_date = datetime.datetime(2013, 10, 2, 2, 23, 15, 423000)                              |
            |             | file_ext ='.jpg'                                                                           |
            |             | file_name = '8cc8cb20bbd145a980a29f6d6c1b68bd.jpg'                                         |
            |             | file_object = None                                                                         |
            |             | file_path = '/srv/www/public/8cc8cb20bbd145a980a29f6d6c1b68bd.jpg'                         |
            |             | file_size = 5129                                                                           |
            |             | guid_name ='8cc8cb20bbd145a980a29f6d6c1b68bd'                                              |
            |             | html_field = 'file_upload'                                                                 |
            |             | mime_type = 'image/pjpeg'                                                                  |
            |             | orig_name = 'test.jpg'                                                                     |
            |             | thumb_name = '8cc8cb20bbd145a980a29f6d6c1b68bd_th.jpg'                                     |
            |             | thumb_path = '/srv/www/public/8cc8cb20bbd145a980a29f6d6c1b68bd_th.jpg'                     |
            |             | zip_name = None                                                                            |
            |             | zip_path = None                                                                            |
            |             | zip_size = None                                                                            |
            +----------------------------------------------------------------------------------------------------------+
            | first_name  | 'John'                                                                                     |
            +----------------------------------------------------------------------------------------------------------+
            | last_name   | 'Smith'                                                                                    |
            +----------------------------------------------------------------------------------------------------------+
            | password    | '$x-pbkdf2$20$1000$9.i7QtmSZyKEgKPIMY3DBA==$Qn2VqbZLNfq/ZNe9y/MhLf1xeRk.nJmlXNISnNOmJRo='  |
            +----------------------------------------------------------------------------------------------------------+
            | postcode    | '99501'                                                                                    |
            +----------------------------------------------------------------------------------------------------------+
            | state       | 'AK'                                                                                       |
            +----------------------------------------------------------------------------------------------------------+
        
        Geographic configuration::
        
            As of now the configuration available includes only USA. If you have to
            validates other countries, you have build similar configuration files and 
            place them in the corresponding folders.
                
        Postcodes validation warning:: 
        
            If you plan to do USA postcodes validation based on the included YAML 
            file, expect a high memory usage as the file contains ~44000 postcodes.
            A better alternative would be to dump the file in a database, build 
            necessary callables to read the data and instruct formv to use these 
            callables. See formv/configuration.py for an example.
        
        USA postcodes data source::
            
            http://www.boutell.com/zipcodes/zipcode.zip
         
        Notes::
        
            Some code fragments have been "borrowed" from FormEncode.
        
        Source:: 
        
            https://pypi.python.org/pypi/formv
        
        For usage and more examples, see examples & tests.
                
Keywords: HTML form validation conversion transformation schema
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Environment :: Other Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
