
    wdfB                         d Z ddlmZmZmZ ddlmZ ddlm	Z	m
Z
mZmZ d Zd Z G d de          Z G d	 d
e          Z	 	 ddZeddddfdZdS )aH  
Form generation utilities for App Engine's new ``ndb.Model`` class.

The goal of ``model_form()`` is to provide a clean, explicit and predictable
way to create forms based on ``ndb.Model`` classes. No malabarism or black
magic should be necessary to generate a form for models, and to add custom
non-model related fields: ``model_form()`` simply generates a form class
that can be used as it is, or that can be extended directly or even be used
to create other forms using ``model_form()``.

Example usage:

.. code-block:: python

   from google.appengine.ext import ndb
   from wtforms.ext.appengine.ndb import model_form

   # Define an example model and add a record.
   class Contact(ndb.Model):
       name = ndb.StringProperty(required=True)
       city = ndb.StringProperty()
       age = ndb.IntegerProperty(required=True)
       is_admin = ndb.BooleanProperty(default=False)

   new_entity = Contact(key_name='test', name='Test Name', age=17)
   new_entity.put()

   # Generate a form based on the model.
   ContactForm = model_form(Contact)

   # Get a form populated with entity data.
   entity = Contact.get_by_key_name('test')
   form = ContactForm(obj=entity)

Properties from the model can be excluded from the generated form, or it can
include just a set of properties. For example:

.. code-block:: python

   # Generate a form based on the model, excluding 'city' and 'is_admin'.
   ContactForm = model_form(Contact, exclude=('city', 'is_admin'))

   # or...

   # Generate a form based on the model, only including 'name' and 'age'.
   ContactForm = model_form(Contact, only=('name', 'age'))

The form can be generated setting field arguments:

.. code-block:: python

   ContactForm = model_form(Contact, only=('name', 'age'), field_args={
       'name': {
           'label': 'Full name',
           'description': 'Your name',
       },
       'age': {
           'label': 'Age',
           'validators': [validators.NumberRange(min=14, max=99)],
       }
   })

The class returned by ``model_form()`` can be used as a base class for forms
mixing non-model fields and/or other model forms. For example:

.. code-block:: python

   # Generate a form based on the model.
   BaseContactForm = model_form(Contact)

   # Generate a form based on other model.
   ExtraContactForm = model_form(MyOtherModel)

   class ContactForm(BaseContactForm):
       # Add an extra, non-model related field.
       subscribe_to_news = f.BooleanField()

       # Add the other model form as a subform.
       extra = f.FormField(ExtraContactForm)

The class returned by ``model_form()`` can also extend an existing form
class:

.. code-block:: python

   class BaseContactForm(Form):
       # Add an extra, non-model related field.
       subscribe_to_news = f.BooleanField()

   # Generate a form based on the model.
   ContactForm = model_form(Contact, base_class=BaseContactForm)

    )Form
validatorsfields)string_types)GeoPtPropertyFieldKeyPropertyFieldStringListPropertyFieldIntegerListPropertyFieldc                     | d                              t          j        d                     t          j        di | S )ze
    Returns a ``TextField``, applying the ``ndb.StringProperty`` length limit
    of 500 bytes.
    r     max )appendr   lengthf	TextField)kwargss    ^/var/www/book.euthymeo.com/html/venv/lib/python3.11/site-packages/wtforms/ext/appengine/ndb.pyget_TextFieldr   c   sA    
 <
 1c : : :;;;;         c                     t          j        dd          }| d                             |           t          j        di | S )z]
    Returns an ``IntegerField``, applying the ``ndb.IntegerProperty`` range
    limits.
    l         l    )minr   r   r   )r   NumberRanger   r   IntegerField)r   vs     r   get_IntegerFieldr   l   sJ    
 	#6<NOOOA
<""">##F###r   c                       e Zd ZddZd ZdS )ModelConverterBaseNc                     i | _         t          |           D ]8}|                    d          st          | |          | j         |dd         <   9dS )z
        Constructs the converter, setting the converter callables.

        :param converters:
            A dictionary of converter callables for each property type. The
            callable must accept the arguments (model, prop, kwargs).
        convert_   N)
convertersdir
startswithgetattr)selfr#   names      r   __init__zModelConverterBase.__init__w   sb     II 	< 	<D??:.. (/d(;(;DODH%%	< 	<r   c                    t          |          j        }|dk    r,|                    d          }|r|                    d          }|j                            dd                                          |j        g d}|r|                    |           |j        r5|| j	        vr,|d         
                    t          j                               |                    dd          r3d	 |                    d          D             |d<   t          j        di |S |j        r%d
 |j        D             |d<   t          j        di |S | j                            |d          }| ||||          S |                     |||          S )aD  
        Returns a form field for a single model property.

        :param model:
            The ``db.Model`` class that contains the property.
        :param prop:
            The model property: a ``db.Property`` instance.
        :param field_args:
            Optional keyword arguments to construct the field.
        GenericPropertytype_ )labeldefaultr   r   choicesNc                     g | ]}||fS r   r   .0r   s     r   
<listcomp>z.ModelConverterBase.convert.<locals>.<listcomp>   s     G G GA!Q G G Gr   c                     g | ]}||fS r   r   r3   s     r   r5   z.ModelConverterBase.convert.<locals>.<listcomp>   s     ? ? ?A!Q ? ? ?r   r   )r,   __name__get
_code_namereplacetitle_defaultupdate	_requiredNO_AUTO_REQUIREDr   r   requiredr   SelectField_choicesr#   fallback_converter)r'   modelprop
field_argsprop_type_namegeneric_typer   	converters           r   convertzModelConverterBase.convert   s    d, ...%>>&11L 8!+!7!7
 _,,S#66<<>>}
 

  	&MM*%%%> 	?nD4III< ''
(;(=(=>>>::i&& 	+ G GI1F1F G G GF9=**6***= 
	D ? ? ? ? ?F9=**6*** ++NDAAI$ yf555..udFCCCr   N)r7   
__module____qualname__r)   rJ   r   r   r   r   r   v   s<        < < < <1D 1D 1D 1D 1Dr   r   c                       e Zd ZdZ eg d          Zd Zd Zd Zd Z	d Z
d Zd	 Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd ZdS )ModelConvertera?  
    Converts properties from a ``ndb.Model`` class to form fields.

    Default conversions between properties and fields:

    +====================+===================+==============+==================+
    | Property subclass  | Field subclass    | datatype     | notes            |
    +====================+===================+==============+==================+
    | StringProperty     | TextField         | unicode      | TextArea         | repeated support
    |                    |                   |              | if multiline     |
    +--------------------+-------------------+--------------+------------------+
    | BooleanProperty    | BooleanField      | bool         |                  |
    +--------------------+-------------------+--------------+------------------+
    | IntegerProperty    | IntegerField      | int or long  |                  | repeated support
    +--------------------+-------------------+--------------+------------------+
    | FloatProperty      | TextField         | float        |                  |
    +--------------------+-------------------+--------------+------------------+
    | DateTimeProperty   | DateTimeField     | datetime     | skipped if       |
    |                    |                   |              | auto_now[_add]   |
    +--------------------+-------------------+--------------+------------------+
    | DateProperty       | DateField         | date         | skipped if       |
    |                    |                   |              | auto_now[_add]   |
    +--------------------+-------------------+--------------+------------------+
    | TimeProperty       | DateTimeField     | time         | skipped if       |
    |                    |                   |              | auto_now[_add]   |
    +--------------------+-------------------+--------------+------------------+
    | TextProperty       | TextAreaField     | unicode      |                  |
    +--------------------+-------------------+--------------+------------------+
    | GeoPtProperty      | TextField         | db.GeoPt     |                  |
    +--------------------+-------------------+--------------+------------------+
    | KeyProperty        | KeyProperyField   | ndb.Key      |                  |
    +--------------------+-------------------+--------------+------------------+
    | BlobKeyProperty    | None              | ndb.BlobKey  | always skipped   |
    +--------------------+-------------------+--------------+------------------+
    | UserProperty       | None              | users.User   | always skipped   |
    +--------------------+-------------------+--------------+------------------+
    | StructuredProperty | None              | ndb.Model    | always skipped   |
    +--------------------+-------------------+--------------+------------------+
    | LocalStructuredPro | None              | ndb.Model    | always skipped   |
    +--------------------+-------------------+--------------+------------------+
    | JsonProperty       | TextField         | unicode      |                  |
    +--------------------+-------------------+--------------+------------------+
    | PickleProperty     | None              | bytedata     | always skipped   |
    +--------------------+-------------------+--------------+------------------+
    | GenericProperty    | None              | generic      | always skipped   |
    +--------------------+-------------------+--------------+------------------+
    | ComputedProperty   | none              |              | always skipped   |
    +====================+===================+==============+==================+

    )ListPropertyStringListPropertyBooleanPropertyc                     |j         rt          di |S |d                             t          j        d                     t          |          S )z2Returns a form field for a ``ndb.StringProperty``.r   r   r   r   )	_repeatedr	   r   r   r   r   r'   rD   rE   r   s       r   convert_StringPropertyz%ModelConverter.convert_StringProperty   sU    > 	5*44V444|##J$5#$>$>$>???V$$$r   c                 $    t          j        di |S )z3Returns a form field for a ``ndb.BooleanProperty``.r   )r   BooleanFieldrU   s       r   convert_BooleanPropertyz&ModelConverter.convert_BooleanProperty   s    ~'''''r   c                 F    |j         rt          di |S t          |          S )z3Returns a form field for a ``ndb.IntegerProperty``.r   )rT   r
   r   rU   s       r   convert_IntegerPropertyz&ModelConverter.convert_IntegerProperty   s.    > 	6+55f555'''r   c                 $    t          j        di |S )z1Returns a form field for a ``ndb.FloatProperty``.r   )r   
FloatFieldrU   s       r   convert_FloatPropertyz$ModelConverter.convert_FloatProperty  s    |%%f%%%r   c                 H    |j         s|j        rdS t          j        dddi|S )z4Returns a form field for a ``ndb.DateTimeProperty``.Nformatz%Y-%m-%d %H:%M:%Sr   	_auto_now_auto_now_addr   DateTimeFieldrU   s       r   convert_DateTimePropertyz'ModelConverter.convert_DateTimeProperty  s7    > 	T/ 	4DD&9DVDDDr   c                 H    |j         s|j        rdS t          j        dddi|S )z0Returns a form field for a ``ndb.DateProperty``.Nr`   z%Y-%m-%dr   )rb   rc   r   	DateFieldrU   s       r   convert_DatePropertyz#ModelConverter.convert_DateProperty  s6    > 	T/ 	4{77*7777r   c                 H    |j         s|j        rdS t          j        dddi|S )z0Returns a form field for a ``ndb.TimeProperty``.Nr`   z%H:%M:%Sr   ra   rU   s       r   convert_TimePropertyz#ModelConverter.convert_TimeProperty  s6    > 	T/ 	4;;j;F;;;r   c                     dS 0Returns a form field for a ``ndb.ListProperty``.Nr   rU   s       r   convert_RepeatedPropertyz'ModelConverter.convert_RepeatedProperty      tr   c                     dS )z0Returns a form field for a ``ndb.UserProperty``.Nr   rU   s       r   convert_UserPropertyz#ModelConverter.convert_UserProperty  ro   r   c                     dS rl   r   rU   s       r   convert_StructuredPropertyz)ModelConverter.convert_StructuredProperty"  ro   r   c                     dS rl   r   rU   s       r   convert_LocalStructuredPropertyz.ModelConverter.convert_LocalStructuredProperty&  ro   r   c                     dS rl   r   rU   s       r   convert_JsonPropertyz#ModelConverter.convert_JsonProperty*  ro   r   c                     dS rl   r   rU   s       r   convert_PicklePropertyz%ModelConverter.convert_PickleProperty.  ro   r   c                 |    |d                              t          j        d                     t          |          S )rm   r   r   r   )r   r   r   r   rU   s       r   convert_GenericPropertyz&ModelConverter.convert_GenericProperty2  s7    |##J$5#$>$>$>???V$$$r   c                 $    t          j        di |S )z3Returns a form field for a ``ndb.BlobKeyProperty``.r   )r   	FileFieldrU   s       r   convert_BlobKeyPropertyz&ModelConverter.convert_BlobKeyProperty7  s    {$$V$$$r   c                 $    t          j        di |S )z0Returns a form field for a ``ndb.TextProperty``.r   )r   TextAreaFieldrU   s       r   convert_TextPropertyz#ModelConverter.convert_TextProperty;  s    (((((r   c                     dS )z4Returns a form field for a ``ndb.ComputedProperty``.Nr   rU   s       r   convert_ComputedPropertyz'ModelConverter.convert_ComputedProperty?  ro   r   c                     t          di |S )z1Returns a form field for a ``ndb.GeoPtProperty``.r   )r   rU   s       r   convert_GeoPtPropertyz$ModelConverter.convert_GeoPtPropertyC  s    !++F+++r   c                     d|vrc	 |j         }n# t          $ r
 |j        }Y nw xY wt          |t                    r)t          |j        dd|gd          }t          ||          }||d<   |                    d|j	                    t          di |S )z/Returns a form field for a ``ndb.KeyProperty``.reference_classNr   allow_blankr   )_kindAttributeError_reference_class
isinstancer   
__import__rL   r&   
setdefaultr>   r   )r'   rD   rE   r   r   mods         r   convert_KeyPropertyz"ModelConverter.convert_KeyPropertyG  s    F**8"&*! 8 8 8"&"78 /<88 @ !14?PRSTT")#"?"?(7F$%-T^);<<<))&)))s    ""N)r7   rL   rM   __doc__	frozensetr?   rV   rY   r[   r^   re   rh   rj   rn   rq   rs   ru   rw   ry   r{   r~   r   r   r   r   r   r   r   rO   rO      sX       1 1f !y!Z!Z!Z[[% % %( ( (( ( (& & &E E E8 8 8< < <            % % %
% % %) ) )  , , ,* * * * *r   rO   Nc                   	 |pt                      }|pi }| j        }t          d t          |                                d           D                       	|rt          	fd|D                       	nrt          fd	D                       	i }	D ]9}|                    | ||         |                    |                    }||||<   :|S )a  
    Extracts and returns a dictionary of form fields for a given
    ``db.Model`` class.

    :param model:
        The ``db.Model`` class to extract fields from.
    :param only:
        An optional iterable with the property names that should be included in
        the form. Only these properties will have fields.
    :param exclude:
        An optional iterable with the property names that should be excluded
        from the form. All other properties will have fields.
    :param field_args:
        An optional dictionary of field names mapping to a keyword arguments
        used to construct each field object.
    :param converter:
        A converter to generate the fields based on the model properties. If
        not set, ``ModelConverter`` is used.
    c              3   &   K   | ]}|d          V  dS )r   Nr   )r4   xs     r   	<genexpr>zmodel_fields.<locals>.<genexpr>s  s&      aaqtaaaaaar   c                     | d         j         S )N   )_creation_counter)r   s    r   <lambda>zmodel_fields.<locals>.<lambda>s  s    1I_ r   )keyc              3   $   K   | ]
}|v |V  d S rK   r   )r4   r   field_namess     r   r   zmodel_fields.<locals>.<genexpr>v  s-      ??a;.>.>1.>.>.>.>??r   c              3   $   K   | ]
}|v|V  d S rK   r   )r4   r   excludes     r   r   zmodel_fields.<locals>.<genexpr>x  s-      FFQg5E5E15E5E5E5EFFr   )rO   _propertieslistsorteditemsrJ   r8   )
rD   onlyr   rF   rI   props
field_dictr(   fieldr   s
     `      @r   model_fieldsr   X  s   * -^--I!rJ EaaVEKKMM?_?_%`%`%`aaaaaK G????d?????	 GFFFFkFFFFF J % %!!%tjnnT6J6JKK$Jtr   c                 v    t          | ||||          }t          |                                 dz   |f|          S )a.  
    Creates and returns a dynamic ``wtforms.Form`` class for a given
    ``ndb.Model`` class. The form class can be used as it is or serve as a base
    for extended form classes, which can then mix non-model related fields,
    subforms with other model forms, among other possibilities.

    :param model:
        The ``ndb.Model`` class to generate a form for.
    :param base_class:
        Base form class to extend from. Must be a ``wtforms.Form`` subclass.
    :param only:
        An optional iterable with the property names that should be included in
        the form. Only these properties will have fields.
    :param exclude:
        An optional iterable with the property names that should be excluded
        from the form. All other properties will have fields.
    :param field_args:
        An optional dictionary of field names mapping to keyword arguments
        used to construct each field object.
    :param converter:
        A converter to generate the fields based on the model properties. If
        not set, ``ModelConverter`` is used.
    r   )r   r,   	_get_kind)rD   
base_classr   r   rF   rI   r   s          r   
model_formr     s>    4 eT7J	JJJ !!F*ZM:FFFr   )NNNN)r   wtformsr   r   r   r   wtforms.compatr   wtforms.ext.appengine.fieldsr   r   r	   r
   r   r   objectr   rO   r   r   r   r   r   <module>r      si  \ \z 2 1 1 1 1 1 1 1 1 1 ' ' ' ' ' ' A  A  A  A  A  A  A  A  A  A  A  A! ! !$ $ $AD AD AD AD AD AD AD ADH[* [* [* [* [*' [* [* [*| =A) ) ) )X "&D$4G G G G G Gr   