a
    ΝGd\                     @   s,  d dl Z d dlZd dlZd dlmZ d dlmZmZ d dl	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mZ d dlmZ d d	lmZ d
dlmZ d
dlmZ d
dlmZ d
dl m!Z!m"Z"m#Z# d
dlm$Z$m%Z% d
dl&m'Z'm(Z(m)Z) e*e+Z,e-dZ.G dd deZG dd de/Z0dS )    N)OrderedDictdefaultdict)
URLPatternURLResolver)
versioning)SchemaGenerator)EndpointEnumerator)endpoint_orderingget_pk_name)get_pk_description)api_settings   )openapi)swagger_settings)SwaggerGenerationError)get_basic_type_infoget_queryset_fieldget_queryset_from_view)ReferenceResolverSwaggerDict)force_real_strget_consumesget_producesz{(?P<parameter>\w+)}c                       sZ   e Zd Zd fdd	Z fddZd fdd	Zd	d
 ZdddZdd Zdd Z	  Z
S )r   Nc                    s   t t| || || _d S N)superr   __init__request)selfpatternsurlconfr   	__class__ O/var/www/html/django/DPS/env/lib/python3.9/site-packages/drf_yasg/generators.pyr      s    zEndpointEnumerator.__init__c                    s,   | drtd| | tt| |S )N)zEurl pattern does not end in $ ('%s') - unexpected things might happen)endswithloggerwarningunescape_pathr   r   get_path_from_regex)r   
path_regexr    r"   r#   r)   !   s    
z&EndpointEnumerator.get_path_from_regex c                    sx   t t| ||sdS t| jdd }t|jdd }|d ur\t|tjr\|r\||	dvr\dS t|jdt
 d u rtdS dS )NFversionversioning_class:swagger_schemaT)r   r   should_include_endpointgetattrr   cls
issubclassr   ZNamespaceVersioningsplitobject)r   pathcallbackapp_name	namespaceurl_namer,   r-   r    r"   r#   r0   &   s    z*EndpointEnumerator.should_include_endpointc                 C   sv   t |jdd}|durrt|tjrrt | jdd}|rrt |dd}d| }||vrftd|j||f  |||}|S )a"  If ``request.version`` is not ``None`` and `callback` uses ``URLPathVersioning``, this function replaces
        the ``version`` parameter in `path` with the actual version.

        :param str path: the templated path
        :param callback: the view callback
        :rtype: str
        r-   Nr,   version_param{%s}z9view %s uses URLPathVersioning but URL %s has no param %s)	r1   r2   r3   r   ZURLPathVersioningr   r&   inforeplace)r   r6   r7   r-   r,   r;   r"   r"   r#   replace_version5   s    
z"EndpointEnumerator.replace_versionc              	   C   s`  |du r| j }g }|du r t }|D ](}|t|j }t|trzz| |}	|j}
|j}| 	|	|
|phd|pnd|r| 
|	|
}	|	|v rW q$||	 | |
D ]}|	||
f}|| qW n  ty   tjddd Y n0 q$t|tr:| j|j||r
d||jf n|j|r"d||jf n|j|d}|| q$tdt| q$t|td	}|S )
z
        Return a list of all available API endpoints by inspecting the URL conf.

        Copied entirely from super.
        Nr+   zfailed to enumerate viewT)exc_infoz%s:%s)r   prefixr8   r9   ignored_endpointszunknown pattern type {}key)r   setstrpattern
isinstancer   r)   r7   namer0   r?   addZget_allowed_methodsappend	Exceptionr&   r'   r   get_api_endpointsZurl_patternsr8   r9   extendformattypesortedr	   )r   r   rA   r8   r9   rB   Zapi_endpointsrG   r*   r6   r7   r:   methodZendpointZnested_endpointsr"   r"   r#   rM   J   sD    




z$EndpointEnumerator.get_api_endpointsc                 C   s   t dd|S )zzUnescape all backslash escapes from `s`.

        :param str s: string with backslash escapes
        :rtype: str
        z\\(.)z\1)resub)r   sr"   r"   r#   unescape}   s    zEndpointEnumerator.unescapec                 C   sb   d}|r^t |}|s&|| |7 }q^|| |d|  7 }|| 7 }|| d }q|S )a  Remove backslashes escapes from all path components outside {parameters}. This is needed because
        ``simplify_regex`` does not handle this correctly.

        **NOTE:** this might destructively affect some url regex patterns that contain metacharacters (e.g. \w, \d)
        outside path parameter groups; if you are in this category, God help you

        :param str path: path possibly containing
        :return: the unescaped path
        :rtype: str
        r+   N)PATH_PARAMETER_REsearchrV   startgroupend)r   r6   Z
clean_pathmatchr"   r"   r#   r(      s    
z EndpointEnumerator.unescape_path)NNN)r+   r+   N)Nr+   NNN)__name__
__module____qualname__r   r)   r0   r?   rM   rV   r(   __classcell__r"   r"   r    r#   r      s   
3	r   c                   @   s   e Zd ZdZeZeZd'ddZe	dd Z
dd	 Zd
d Zd(ddZd)ddZdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& ZdS )*OpenAPISchemaGeneratorz
    This class iterates over all registered API endpoints and returns an appropriate OpenAPI 2.0 compliant schema.
    Method implementations shamelessly stolen and adapted from rest-framework ``SchemaGenerator``.
    r+   Nc                 C   s   t |j||dd||| _|| _|| _g | _g | _|du rLtj	durLtj	}|rt

|}|jdvsj|jsrtd|jrtd|  n|| j_dS )a  

        :param openapi.Info info: information about the API
        :param str version: API version string; if omitted, `info.default_version` will be used
        :param str url: API scheme, host and port; if ``None`` is passed and ``DEFAULT_API_URL`` is not set, the url
            will be inferred from the request made against the schema view, so you should generally not need to set
            this parameter explicitly; if the empty string is passed, no host and scheme will be emitted

            If `url` is not ``None`` or the empty string, it must be a scheme-absolute uri (i.e. starting with http://
            or https://), and any path component is ignored;

            See also: :ref:`documentation on base URL construction <custom-spec-base-url>`
        :param patterns: if given, only these patterns will be enumerated for inclusion in the API spec
        :param urlconf: if patterns is not given, use this urlconf to enumerate patterns;
            if not given, the default urlconf is used
        descriptionr+   N)httphttpsz%`url` must be an absolute HTTP(S) urlzKpath component of api base URL %s is ignored; use FORCE_SCRIPT_NAME instead)r   titleget_genr=   r,   consumesproducesr   ZDEFAULT_API_URLurlparseschemenetlocr   r6   r&   r'   url)r   r=   r,   rm   r   r   
parsed_urlr"   r"   r#   r      s    
zOpenAPISchemaGenerator.__init__c                 C   s   | j jS r   )rg   rm   )r   r"   r"   r#   rm      s    zOpenAPISchemaGenerator.urlc                 C   s   t j}|durt|i }|S )a  Get the security schemes for this API. This determines what is usable in security requirements,
        and helps clients configure their authorization credentials.

        :return: the security schemes usable with this API
        :rtype: dict[str,dict] or None
        N)r   ZSECURITY_DEFINITIONSr   	_as_odict)r   security_definitionsr"   r"   r#   get_security_definitions   s    z/OpenAPISchemaGenerator.get_security_definitionsc                 C   s:   t j}|du rdd |D }dd |D }t|td}|S )aj  Get the base (global) security requirements of the API. This is never called if
        :meth:`.get_security_definitions` returns `None`.

        :param security_definitions: security definitions as returned by :meth:`.get_security_definitions`
        :return: the security schemes accepted by default
        :rtype: list[dict[str,list[str]]] or None
        Nc                 S   s   g | ]}|g iqS r"   r"   ).0Zsecurity_schemer"   r"   r#   
<listcomp>       zDOpenAPISchemaGenerator.get_security_requirements.<locals>.<listcomp>c                 S   s   g | ]}t |i qS r"   )r   ro   )rr   srr"   r"   r#   rs      rt   rC   )r   ZSECURITY_REQUIREMENTSrQ   list)r   rp   security_requirementsr"   r"   r#   get_security_requirements   s    z0OpenAPISchemaGenerator.get_security_requirementsFc           
      C   s   |  |}| jtjdd}ttj| _ttj	| _
| ||||\}}|  }|r^| |}nd}| j}	|	du r|dur| }	tjf | j|| jpd| j
pd|||	|| jd	t|S )a  Generate a :class:`.Swagger` object representing the API schema.

        :param request: the request used for filtering accessible endpoints and finding the spec URI
        :type request: rest_framework.request.Request or None
        :param bool public: if True, all endpoints are included regardless of access through `request`

        :return: the generated Swagger specification
        :rtype: openapi.Swagger
        T)Z
force_initN)	r=   pathsrh   ri   rp   security_url_prefix_version)get_endpointsreference_resolver_classr   ZSCHEMA_DEFINITIONSr   r   ZDEFAULT_PARSER_CLASSESrh   r   ZDEFAULT_RENDERER_CLASSESri   	get_pathsrq   rx   rm   Zbuild_absolute_uriZSwaggerr=   r,   dict)
r   r   public	endpoints
componentsry   rA   rp   rw   rm   r"   r"   r#   
get_schema   s&    

z!OpenAPISchemaGenerator.get_schemac                 C   sh   | j |||}t|dd}|durX| D ]*\}}t||d}|dur,t|jd| q,t|dd |S )aP  Create a view instance from a view callback as registered in urlpatterns.

        :param callback: view callback registered in urlpatterns
        :param str method: HTTP method
        :param request: request to bind to the view
        :type request: rest_framework.request.Request or None
        :return: the view instance
        _swagger_auto_schemaNZswagger_fake_viewT)rg   create_viewr1   itemssetattr__func__)r   r7   rR   r   view	overrides_Zview_methodr"   r"   r#   r   
  s    	z"OpenAPISchemaGenerator.create_viewc                 C   s>   d|vr|S t t|dd}|r*t|}nd}|dd| S )aK  Coerce {pk} path arguments into the name of the model field, where possible. This is cleaner for an
        external representation (i.e. "this is an identifier", not "this is a database primary key").

        :param str path: the path
        :param rest_framework.views.APIView view: associated view
        :rtype: str
        z{pk}modelNidr<   )r1   r   r
   r>   )r   r6   r   r   
field_namer"   r"   r#   coerce_path  s    
z"OpenAPISchemaGenerator.coerce_pathc           	         s   | j | jj| jj|d}| }tt}i  |D ]@\}}}| |||}| ||}|| 	||f |j
 |< q0 fdd| D S )a  Iterate over all the registered endpoints in the API and return a fake view with the right parameters.

        :param request: request to bind to the endpoint views
        :type request: rest_framework.request.Request or None
        :return: {path: (view_class, list[(http_method, view_instance)])
        :rtype: dict[str,(type,list[(str,rest_framework.views.APIView)])]
        )r   c                    s   i | ]\}}| | |fqS r"   r"   )rr   r6   methodsview_clsr"   r#   
<dictcomp>C  rt   z8OpenAPISchemaGenerator.get_endpoints.<locals>.<dictcomp>)endpoint_enumerator_classrg   r   r   rM   r   rv   r   r   rK   r2   r   )	r   r   Z
enumeratorr   Z
view_pathsr6   rR   r7   r   r"   r   r#   r~   1  s    z$OpenAPISchemaGenerator.get_endpointsc                 C   s   | j |||S )aX  Return a list of keys that should be used to group an operation within the specification. ::

          /users/                   ("users", "list"), ("users", "create")
          /users/{pk}/              ("users", "read"), ("users", "update"), ("users", "delete")
          /users/enabled/           ("users", "enabled")  # custom viewset list action
          /users/{pk}/star/         ("users", "star")     # custom viewset detail action
          /users/{pk}/groups/       ("users", "groups", "list"), ("users", "groups", "create")
          /users/{pk}/groups/{pk}/  ("users", "groups", "read"), ("users", "groups", "update")

        :param str subpath: path to the operation with any common prefix/base path removed
        :param str method: HTTP method
        :param view: the view associated with the operation
        :rtype: list[str]
        )rg   Zget_keys)r   subpathrR   r   r"   r"   r#   get_operation_keysE  s    z)OpenAPISchemaGenerator.get_operation_keysc                 C   s   | j |S )a  
        Given a list of all paths, return the common prefix which should be
        discounted when generating a schema structure.

        This will be the longest common string that does not include that last
        component of the URL, or the last component before a path parameter.

        For example: ::

            /api/v1/users/
            /api/v1/users/{pk}/

        The path prefix is ``/api/v1/``.

        :param list[str] paths: list of paths
        :rtype: str
        )rg   determine_path_prefixr   ry   r"   r"   r#   r   V  s    z,OpenAPISchemaGenerator.determine_path_prefixc                 C   s   |p| j |||S )a  Check if a given endpoint should be included in the resulting schema.

        :param str path: request path
        :param str method: http request method
        :param view: instantiated view callback
        :param bool public: if True, all endpoints are included regardless of access through `request`
        :returns: true if the view should be excluded
        :rtype: bool
        )rg   Zhas_view_permissions)r   r6   rR   r   r   r"   r"   r#   r0   j  s    
z.OpenAPISchemaGenerator.should_include_endpointc                 C   s   t j|dS )zConstruct the Swagger Paths object.

        :param OrderedDict[str,openapi.PathItem] paths: mapping of paths to :class:`.PathItem` objects
        :returns: the :class:`.Paths` object
        :rtype: openapi.Paths
        ry   )r   Pathsr   r"   r"   r#   get_paths_objectv  s    z'OpenAPISchemaGenerator.get_paths_objectc              
   C   s   |st ji ddfS | t| p(d}d|vs:J dt }t| D ]\}\}}	i }
|	D ]B\}}| ||||szq`| 	||||||}|dur`||
|
 < q`|
rL|t|d }|dsd| }| |||
||< qL| ||fS )a+  Generate the Swagger Paths for the API from the given endpoints.

        :param dict endpoints: endpoints as returned by get_endpoints
        :param ReferenceResolver components: resolver/container for Swagger References
        :param Request request: the request made against the schema view; can be None
        :param bool public: if True, all endpoints are included regardless of access through `request`
        :returns: the :class:`.Paths` object and the longest common path prefix, as a 2-tuple
        :rtype: tuple[openapi.Paths,str]
        r   r+   {z,base path cannot be templated in swagger 2.0N/)r   r   r   rv   keysr   rQ   r   r0   get_operationlowerlen
startswithget_path_itemr   )r   r   r   r   r   rA   ry   r6   r   r   
operationsrR   r   	operationZpath_suffixr"   r"   r#   r     s&    

z OpenAPISchemaGenerator.get_pathsc                 C   s   |  |t|d ||}| ||}tj}	t|d|	}	|d|	}	|	du rPdS |	|||||||}
|
|}|du rzdS d|v rt|j	t| j	kr|`	d|v rt|j
t| j
kr|`
|S )a  Get an :class:`.Operation` for the given API endpoint (path, method). This method delegates to
        :meth:`~.inspectors.ViewInspector.get_operation` of a :class:`~.inspectors.ViewInspector` determined
        according to settings and :func:`@swagger_auto_schema <.swagger_auto_schema>` overrides.

        :param view: the view associated with this endpoint
        :param str path: the path component of the operation URL
        :param str prefix: common path prefix among all endpoints
        :param str method: the http method of the operation
        :param openapi.ReferenceResolver components: referenceable components
        :param Request request: the request made against the schema view; can be None
        :rtype: openapi.Operation
        Nr/   Zauto_schemarh   ri   )r   r   get_overridesr   ZDEFAULT_AUTO_SCHEMA_CLASSr1   rf   r   rE   rh   ri   )r   r   r6   rA   rR   r   r   Zoperation_keysr   Zview_inspector_clsZview_inspectorr   r"   r"   r#   r     s     
z$OpenAPISchemaGenerator.get_operationc                 C   s    |  ||}tjf d|i|S )a  Get a :class:`.PathItem` object that describes the parameters and operations related to a single path in the
        API.

        :param str path: the path
        :param type view_cls: the view that was bound to this path in urlpatterns
        :param dict[str,openapi.Operation] operations: operations defined on this path, keyed by lowercase HTTP method
        :rtype: openapi.PathItem
        
parameters)get_path_parametersr   ZPathItem)r   r6   r   r   Zpath_parametersr"   r"   r#   r     s    	z$OpenAPISchemaGenerator.get_path_itemc                 C   sF   |  }t|d|}t||d}t|di }||v r<|| }t|S )a"  Get overrides specified for a given operation.

        :param view: the view associated with the operation
        :param str method: HTTP method
        :return: a dictionary containing any overrides set by :func:`@swagger_auto_schema <.swagger_auto_schema>`
        :rtype: dict
        actionNr   )r   r1   copydeepcopy)r   r   rR   r   Zaction_methodr   r"   r"   r#   r     s    z$OpenAPISchemaGenerator.get_overridesc                 C   s   g }t |}tt|D ]}t||\}}t|p<dtji}t|dd|krt|d tjkrtt|d|	dd|d< |rt|ddr|j
}	n |rt|ddrt||}	nd}	tjf |t|	d	tjd
|}
||
 q|S )a  Return a list of Parameter instances corresponding to any templated path variables.

        :param str path: templated request path
        :param type view_cls: the view class associated with the path
        :return: path parameters
        :rtype: list[openapi.Parameter]
        rP   Zlookup_fieldNZlookup_value_regexrG   	help_textFZprimary_keyT)rI   rb   requiredZin_)r   rQ   uritemplate	variablesr   r   r   ZTYPE_STRINGr1   rf   r   r   	Parameterr   ZIN_PATHrK   )r   r6   r   r   Zquerysetvariabler   Zmodel_fieldattrsrb   fieldr"   r"   r#   r     s,    z*OpenAPISchemaGenerator.get_path_parameters)r+   NNN)NF)N)r]   r^   r_   __doc__r   r   r   r   r   propertyrm   rq   rx   r   r   r   r~   r   r   r0   r   r   r   r   r   r   r"   r"   r"   r#   ra      s*   
#

 
	%&ra   )1r   loggingrS   urllib.parseparserj   collectionsr   r   r   Zdjango.urlsr   r   Zrest_frameworkr   Zrest_framework.schemasr   Z!rest_framework.schemas.generatorsr   Z_EndpointEnumeratorr	   r
   Zrest_framework.schemas.utilsr   Zrest_framework.settingsr   r+   r   Zapp_settingsr   errorsr   Zinspectors.fieldr   r   r   r   r   utilsr   r   r   	getLoggerr]   r&   compilerW   r5   ra   r"   r"   r"   r#   <module>   s.   

 