o
    iG                     @   s  d Z ddlmZ ddlZeeZddlZddlm	Z	 ddl
mZmZmZ ddlmZmZmZ zddlmZ W n eyE   edZY nw dd	lmZmZmZ dd
lmZ ddlmZmZ ddlm Z  ddl!m"Z" ddl#m$Z$ ddl%m&Z& edej'Z(dd Z)dd Z*G dd de+Z,G dd de,Z-G dd de-Z.G dd de,Z/G dd de+Z0dd  Z1d!Z2d"ej3fd#ej4fd$ej5d%e1e2d&fd'ej5fd(ej5d)e1e(j6d&fd*ej5d+e1ej6d&fd,ej7fd-ej5fd.ej8fd/ej8fd0ej9fd1ej:fd2ej;fd3ej<fd4ej=fd5ej>fd6ej?fd7ej@fd8ejAfd9ej3fd:ej3ffZBd;d< ZCeCe0eBZDG d=d> d>eZEe&eEG d?d@ d@eZFG dAdB dBeZGG dCdD dDeZG dEdF dFe ZHeHZIdS )Gz}Useful stuff to integrate Spyne with Django.

* Django model <-> spyne type mapping
* Service for common exception handling

    )absolute_importN)chain)ImproperlyConfiguredObjectDoesNotExistValidationError)slug_reMinLengthValidatorMaxLengthValidator)comma_separated_int_list_rez^[\d,]+$)ResourceNotFoundErrorr   Fault)	primitive)ComplexModelMetaComplexModelBase)Service)cdict)odict)add_metaclassz[A-Za-z0-9!#-'\*\+\-/=\?\^_`\{-~]+(\.[A-Za-z0-9!#-'\*\+\-/=\?\^_`\{-~]+)*@([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[A-Za-z]{2,}c                 C   $   | j }|d|}t|||d< d S )Nmin_len)limit_value
setdefaultmax)	validatorparamsnew_minold_min r   Q/var/www/html/LicenciasMIG/venv/lib/python3.10/site-packages/spyne/util/django.py_handle_minlengthE      r   c                 C   r   )Nmax_len)r   r   min)r   r   new_maxold_maxr   r   r   _handle_maxlengthK   r    r%   c                   @   sP   e Zd ZdZeeeeeiZ	e
dd Ze
dd Zdd Zdd	 Zd
d ZdS )BaseDjangoFieldMapperz&Abstrace base class for field mappers.c                 K      | j S )z(Return True if django field is nullable.)nullfieldkwargsr   r   r   is_field_nullableZ      z'BaseDjangoFieldMapper.is_field_nullablec                 K   r'   )z%Return True if django field is blank.)blankr)   r   r   r   is_field_blank_   r-   z$BaseDjangoFieldMapper.is_field_blankc           	      K   s   |  }| |j| | j|fi |}| j|fi |}| p%|p%|j }| r1| |d< | j|fi |}|d|t	|d|}|j
|fS )zMap field to spyne model.

        :param field: Django Field instance
        :param kwargs: Extra params to configure spyne model
        :returns: tuple (field attribute name, mapped spyne model)

        default)nullable
min_occursNr   )copy_process_validators
validatorsr,   r/   has_defaultprimary_keyget_defaultget_spyne_modelintattname)	selfr*   r+   r   r1   r.   requiredspyne_modelcustomized_modelr   r   r   mapd   s   
zBaseDjangoFieldMapper.mapc                 K   s   t )z*Return spyne model for given Django field.)NotImplementedErrorr<   r*   r+   r   r   r   r9   }   s   z%BaseDjangoFieldMapper.get_spyne_modelc                 C   s,   |D ]}| j t|}|r||| qd S N)_VALIDATOR_HANDLERSgettype)r<   r5   r   vhandlerr   r   r   r4      s   
z)BaseDjangoFieldMapper._process_validatorsN)__name__
__module____qualname____doc__r   r   r   r	   r%   rD   staticmethodr,   r/   r@   r9   r4   r   r   r   r   r&   Q   s    

r&   c                   @   s    e Zd ZdZdd Zdd ZdS )DjangoFieldMapperzBasic mapper for django fields.c                 C   
   || _ dS )z Django field mapper constructor.Nr>   )r<   r>   r   r   r   __init__      
zDjangoFieldMapper.__init__c                 K   r'   )zReturn configured spyne model.rP   rB   r   r   r   r9      s   z!DjangoFieldMapper.get_spyne_modelN)rI   rJ   rK   rL   rQ   r9   r   r   r   r   rN      s    rN   c                           e Zd ZdZ fddZ  ZS )DecimalMapperzMapper for DecimalField.c                    s4   |  }||j|jd tt| j|fi |S )znMap DecimalField to spyne model.

        :returns: tuple (field attribute name, mapped spyne model)

        )total_digitsfraction_digits)r3   update
max_digitsdecimal_placessuperrT   r@   )r<   r*   r+   r   	__class__r   r   r@      s   zDecimalMapper.map)rI   rJ   rK   rL   r@   __classcell__r   r   r[   r   rT          rT   c                   @   s,   e Zd ZdZdd Zedd Zdd ZdS )	RelationMapperz7Mapper for relation fields (ForeignKey, OneToOneField).c                 C   rO   )z&Constructor for relation field mapper.N)django_model_mapper)r<   r`   r   r   r   rQ      rR   zRelationMapper.__init__c                 K   s"   | dd}|ptj| fi |S )z]Return True if `optional_relations` is set.

        Otherwise use basic behaviour.

        optional_relationsF)rE   r&   r/   )r*   r+   ra   r   r   r   r/      s   zRelationMapper.is_field_blankc                 K   sL   t |dr
|j n|j }|jj}| j|}|j|fi |\}}|S )z/Return spyne model configured by related field.rel)	hasattrrb   get_related_fieldremote_fieldr\   rI   r`   get_field_mapperr@   )r<   r*   r+   related_field
field_typefield_mapper_related_spyne_modelr   r   r   r9      s
   zRelationMapper.get_spyne_modelN)rI   rJ   rK   rL   rQ   rM   r/   r9   r   r   r   r   r_      s    

r_   c                   @   sj   e Zd ZdZeZG dd deZdddZdd Z	d	d
 Z
dd Zedd ZedddZdddZdS )DjangoModelMapperaQ  Mapper from django models to spyne complex models.

    You can extend it registering new field types: ::

        class NullBooleanMapper(DjangoFieldMapper):

            def map(self, field, **kwargs):
                params = kwargs.copy()
                # your mapping logic goes here
                return super(NullBooleanMapper, self).map(field, **params)

        default_model_mapper.register_field_mapper('NullBooleanField', \
                NullBooleanMapper(primitive.Boolean))


    You may subclass it if you want different mapping logic for different
    Django models.

    c                   @   s   e Zd ZdZdS )z-DjangoModelMapper.UnknownFieldMapperExceptionz;Raises when there is no field mapper for given django_type.N)rI   rJ   rK   rL   r   r   r   r   UnknownFieldMapperException   s    rm   r   c                 C   s$   i | _ |D ]
\}}| || qdS )z,Register field mappers in internal registry.N)	_registryregister)r<   django_spyne_modelsdjango_typer>   r   r   r   rQ      s   zDjangoModelMapper.__init__c                 C   s,   z| j | W S  ty   | d|w )zGet mapper registered for given django_type.

        :param django_type: Django internal field type
        :returns: registered mapper
        :raises: :exc:`UnknownFieldMapperException`

        No mapper for field type {0})rn   KeyErrorrm   format)r<   rq   r   r   r   rf      s   z"DjangoModelMapper.get_field_mapperc                 C   s   |  |}| || dS )zRegister default field mapper for django_type and spyne_model.

        :param django_type: Django internal field type
        :param spyne_model: Spyne model, usually primitive

        N)field_mapper_classregister_field_mapper)r<   rq   r>   ri   r   r   r   ro      s   
zDjangoModelMapper.registerc                 C   s   || j |< dS )zRegister field mapper for django_type.

        :param django_type: Django internal field type
        :param field_mapper: :class:`DjangoFieldMapper` instance

        N)rn   )r<   rq   ri   r   r   r   rv      s   z'DjangoModelMapper.register_field_mapperc                 C   s2   t | dr	|  S tttdd |  D S )Nget_all_field_namesc                 s   s>    | ]}|j r|jd u st|dr|j|jfn|jfV  qd S )Nr;   )many_to_onerelated_modelrc   namer;   .0r*   r   r   r   	<genexpr>  s    
z8DjangoModelMapper.get_all_field_names.<locals>.<genexpr>)rc   rw   listsetr   from_iterable
get_fields)metar   r   r   rw     s
   
z%DjangoModelMapper.get_all_field_namesNc                    sX   |d urt |nt   | j} t|}|r"tdd| fdd|jD S )NzUnknown field names: {0}z, c                    s   g | ]	}|j  vr|qS r   )rz   r{   field_namesr   r   
<listcomp>"  s    z1DjangoModelMapper._get_fields.<locals>.<listcomp>)	r   _meta
differencerl   rw   r   rt   joinfields)django_modelexcluder   unknown_fields_namesr   r   r   _get_fields  s   zDjangoModelMapper._get_fieldsc           
   	   K   s   t  }| ||D ]:}|jj}z| j| }W n ty3   | s,|js,| d	|t
d Y q	w |j|fi |\}}	|	||< q	|S )af  Prepare dict of model fields mapped to spyne models.

        :param django_model: Django model class.
        :param exclude: list of fields excluded from mapping.
        :param kwargs: extra kwargs are passed to all field mappers

        :returns: dict mapping attribute names to spyne models
        :raises: :exc:`UnknownFieldMapperException`

        rr   z"Field {0} is skipped from mapping.)r   r   r\   rI   rn   rs   r6   r(   rm   rt   loggerinfor@   )
r<   r   r   r+   	field_mapr*   rh   ri   	attr_namer>   r   r   r   r@   %  s    

zDjangoModelMapper.map)r   rC   )rI   rJ   rK   rL   rN   ru   	Exceptionrm   rQ   rf   ro   rv   rM   rw   r   r@   r   r   r   r   rl      s    

	
rl   c                 C   s8   d}t | }| drd}| dr|d8 }| || S )zStrip ^ and $ from pattern begining and end.

    According to http://www.w3.org/TR/xmlschema-0/#regexAppendix XMLSchema
    expression language does not contain the metacharacters ^ and $.

    :returns: stripped pattern string

    r   ^   $)len
startswithendswith)patternstarttillr   r   r   strip_regex_metacharsH  s   	

r   z[a-zA-Z0-9_-]+	AutoField	CharField	SlugFieldSlug)	type_namer   	TextField
EmailFieldEmailCommaSeparatedIntegerFieldCommaSeparatedFieldURLFieldFilePathFieldBooleanFieldNullBooleanFieldIntegerFieldBigIntegerFieldPositiveIntegerFieldSmallIntegerFieldPositiveSmallIntegerField
FloatField	TimeField	DateFieldDateTimeField
ForeignKeyOneToOneFieldc                 C   s>   | |}| dt| | dt| | dttj |S )zpFactory for model mappers.

    The factory is useful to create custom field mappers based on default one.

    r   r   DecimalField)rv   r_   rT   r   Decimal)mapper_classr   model_mapperr   r   r   model_mapper_factory  s   r   c                       rS   )DjangoComplexModelMetaz?Meta class for complex spyne models representing Django models.c                    s   t t| j}t|dd}|r|| |||S |d}|du r$tdt|dddu r0tdt|dt}||_t|d	d}t|d
d}	|j	|j
||	d}
|
| || |||
S )z7Populate new complex type from configured Django model.__abstract__F
AttributesNzAYou have to define Attributes and specify Attributes.django_modelr   z7You have to define django_model attribute in Attributesdjango_mapperdjango_excludedjango_optional_relations)r   ra   )rZ   r   __new__boolrE   r   getattrdefault_model_mapperr   r@   r   rW   )mcsrz   basesattrs	super_newabstract
attributesmapperr   ra   spyne_attrsr[   r   r   r     s(   


zDjangoComplexModelMeta.__new__)rI   rJ   rK   rL   r   r]   r   r   r[   r   r     r^   r   c                   @   s   e Zd ZdZdZdS )DjangoComplexModelae  Base class with Django model mapping support.

    Sample usage: ::

        class PersonType(DjangoComplexModel):
            class Attributes(DjangoComplexModel.Attributes):
                django_model = Person


    Attribute :attr:`django_model` is required for Django model mapping
    machinery. You can customize your types defining custom type fields: ::

        class PersonType(DjangoComplexModel):
            gender = primitive.Unicode(pattern='^[FM]$')

            class Attributes(DjangoComplexModel.Attributes):
                django_model = Person


    There is an option to specify custom mapper: ::

        class PersonType(DjangoComplexModel):
            class Attributes(DjangoComplexModel.Attributes):
                django_model = Person
                django_mapper = my_custom_mapper

    You can also exclude some fields from mapping: ::

        class PersonType(DjangoComplexModel):
            class Attributes(DjangoComplexModel.Attributes):
                django_model = Person
                django_exclude = ['phone']

    You may set `django_optional_relations`` attribute flag to indicate
    that relation fields (ForeignKey, OneToOneField) of your model are
    optional.  This is useful when you want to create base and related
    instances in remote procedure. In this case primary key of base model is
    not yet available.

    TN)rI   rJ   rK   rL   r   r   r   r   r   r     s    )r   c                   @      e Zd ZdZdd ZdS )ObjectNotFoundErrorz6Fault constructed from `model.DoesNotExist` exception.c                 C   s.   t |}| d }tj| d||d dS )z7Construct fault with code Client.<object_name>NotFound.r   zClient.{0}NotFound	faultcodefaultstringN)strsplitr   rQ   rt   )r<   does_not_exist_excmessageobject_namer   r   r   rQ     s   

zObjectNotFoundError.__init__NrI   rJ   rK   rL   rQ   r   r   r   r   r         r   c                   @   r   )r   z3Fault constructed from `ValidationError` exception.c                 C   s(   t |}tj| dt|j|d dS )z>Construct fault with code Client.<validation_error_type_name>.z
Client.{0}r   N)r   r   rQ   rt   rF   rI   )r<   validation_error_excr   r   r   r   rQ      s   
zValidationError.__init__Nr   r   r   r   r   r     r   r   c                       s$   e Zd ZdZe fddZ  ZS )DjangoServicez.Service with common Django exception handling.c              
      sV   zt t| |}W |S  ty } zt|d}~w ty* } zt|d}~ww )z Handle common Django exceptions.N)rZ   r   call_wrapperr   r   DjValidationErrorr   )clsctx
out_objecter[   r   r   r     s   zDjangoService.call_wrapper)rI   rJ   rK   rL   classmethodr   r]   r   r   r[   r   r   	  s    r   )JrL   
__future__r   logging	getLoggerrI   r   re	itertoolsr   django.core.exceptionsr   r   r   r   django.core.validatorsr   r   r	   r
   ImportErrorcompilespyne.errorr   BaseValidationErrorr   spyne.modelr   spyne.model.complexr   r   spyne.servicer   spyne.util.cdictr   spyne.util.odictr   spyne.util.sixr   
IGNORECASEemail_rer   r%   objectr&   rN   rT   r_   rl   r   SLUG_RE_PATTERN	Integer32NormalizedStringUnicoder   AnyUriBooleanInteger	Integer64UnsignedInteger32	Integer16UnsignedInteger16DoubleTimeDateDateTimeDEFAULT_FIELD_MAPr   r   r   r   r   r   DjangoServiceBaser   r   r   r   <module>   s   
	7 
!#.