
    phS                        S r SSKJr  SSKrSSKrSSKrSSKJr  SSK	J
r
  \R                  S V s0 s H  o S_M     sn 5      r " S S	\5      r " S
 S\5      rS rSrgs  sn f )z"
Utilities to support XYZservices
    )annotationsN)Callable)quotez., -_/ c                  j    \ rS rSrSrS rS rSS jrSS jr    S         SS jjr	SS	 jr
S
rg)Bunch   a[  A dict with attribute-access

:class:`Bunch` is used to store :class:`TileProvider` objects.

Examples
--------
>>> black_and_white = TileProvider(
...     name="My black and white tiles",
...     url="https://myserver.com/bw/{z}/{x}/{y}",
...     attribution="(C) xyzservices",
... )
>>> colorful = TileProvider(
...     name="My colorful tiles",
...     url="https://myserver.com/color/{z}/{x}/{y}",
...     attribution="(C) xyzservices",
... )
>>> MyTiles = Bunch(BlackAndWhite=black_and_white, Colorful=colorful)
>>> MyTiles
{'BlackAndWhite': {'name': 'My black and white tiles', 'url': 'https://myserver.com/bw/{z}/{x}/{y}', 'attribution': '(C) xyzservices'}, 'Colorful': {'name': 'My colorful tiles', 'url': 'https://myserver.com/color/{z}/{x}/{y}', 'attribution': '(C) xyzservices'}}
>>> MyTiles.BlackAndWhite.url
'https://myserver.com/bw/{z}/{x}/{y}'
c                b     U R                  U5      $ ! [         a  n[        U5      UeS nAff = fN)__getitem__KeyErrorAttributeError)selfkeyerrs      gC:\Users\julio\OneDrive\Documentos\Trabajo\IdeasFrscas\Cabanna\env\Lib\site-packages\xyzservices/lib.py__getattr__Bunch.__getattr__+   s5    	/##C(( 	/ %3.	/s    
.).c                "    U R                  5       $ r   )keysr   s    r   __dir__Bunch.__dir__1   s    yy{    c                (   SnU  Ha  n[        X   [        5      (       a  SnOSn[        [        R                  " 5       5      nUSU SU SU SU SX   R                  S	S
9 S3-  nMc     U(       a  SO	S[         S3nSU S[        U 5       SU S3nU$ )Nr   zxyzservices.TileProviderzxyzservices.BunchzO
            <li class="xyz-child">
                <input type="checkbox" id="z5" class="xyz-checkbox"/>
                <label for="z">z <span>zM</span></label>
                <div class="xyz-inside">
                    T)insidez6
                </div>
            </li>
            <style></style>
        <div>
        z
            <div class="xyz-wrap">
                <div class="xyz-header">
                    <div class="xyz-obj">xyzservices.Bunch</div>
                    <div class="xyz-name">z items</div>
                </div>
                <div class="xyz-details">
                    <ul class="xyz-collapsible">
                        z\
                    </ul>
                </div>
            </div>
        </div>
        )
isinstanceTileProviderstruuiduuid4_repr_html_	CSS_STYLElen)r   r   childrenr   objuidstylehtmls           r   r%   Bunch._repr_html_4   s    C$)\220)djjl#C ,,/5 1 EC5u 5Y**$*78 9 H   GI;h"?		 + ,/t9+ 6 "
 #	" r   c                ,   ^^ 0 mUU4S jmT" U 5        T$ )a  Return the nested :class:`Bunch` collapsed into the one level dictionary.

Dictionary keys are :class:`TileProvider` names (e.g. ``OpenStreetMap.Mapnik``)
and its values are :class:`TileProvider` objects.

Returns
-------
flattened : dict
    dictionary of :class:`TileProvider` objects

Examples
--------
>>> import xyzservices.providers as xyz
>>> len(xyz)
36

>>> flat = xyz.flatten()
>>> len(xyz)
207

c                   > [        U [        5      (       a  U TU R                  '   g U R                  5        H  nT" U5        M     g r   )r    r!   namevalues)providerprov_get_providersflats     r   r4   %Bunch.flatten.<locals>._get_providerss   s7    (L11&.X]]#$OO-D"4( .r    )r   r4   r5   s    @@r   flattenBunch.flattenZ   s    . 	) 	tr   Nc                .   ^^ S mUU4S jmT" U UUUUS9$ )a  Return a subset of the :class:`Bunch` matching the filter conditions

Each :class:`TileProvider` within a :class:`Bunch` is checked against one or
more specified conditions and kept if they are satisfied or removed if at least
one condition is not met.

Parameters
----------
keyword : str (optional)
    Condition returns ``True`` if ``keyword`` string is present in any string
    value in a :class:`TileProvider` object.
    The comparison is not case sensitive.
name : str (optional)
    Condition returns ``True`` if ``name`` string is present in
    the name attribute of :class:`TileProvider` object.
    The comparison is not case sensitive.
requires_token : bool (optional)
    Condition returns ``True`` if :meth:`TileProvider.requires_token` returns
    ``True`` (i.e. if the object requires specification of API token).
function : callable (optional)
    Custom function taking :class:`TileProvider` as an argument and returns
    bool. If ``function`` is given, other parameters are ignored.

Returns
-------
filtered : Bunch

Examples
--------
>>> import xyzservices.providers as xyz

You can filter all free providers (not requiring API token):

>>> free_providers = xyz.filter(requires_token=False)

Or all providers with ``open`` in the name:

>>> open_providers = xyz.filter(name="open")

You can use keyword search to find all providers based on OpenStreetMap data:

>>> osm_providers = xyz.filter(keyword="openstreetmap")

You can combine multiple conditions to find providers based on OpenStreetMap
data that require API token:

>>> osm_locked = xyz.filter(keyword="openstreetmap", requires_token=True)

You can also pass custom function that takes :class:`TileProvider` and returns
boolean value. You can then find all providers with ``max_zoom`` smaller than
18:

>>> def zoom18(provider):
...    if hasattr(provider, "max_zoom") and provider.max_zoom < 18:
...        return True
...    return False
>>> small_zoom = xyz.filter(function=zoom18)
c                   / nUbg  SnU R                  5        H@  n[        U[        5      (       d  M  UR                  5       UR                  5       ;   d  M>  Sn  O   UR	                  U5        UbA  SnUR                  5       U R
                  R                  5       ;   a  SnUR	                  U5        Ub(  SnU R                  5       UL a  SnUR	                  U5        [        U5      $ )NFT)r1   r    r"   lowerappendr0   requires_tokenall)	r2   keywordr0   r>   condkeyword_matchv
name_matchtoken_matchs	            r   	_validateBunch.filter.<locals>._validate   s    D" %!*A!!S))gmmo.J(, + M*"
::<8==#6#6#88!%JJ')#**,>"&KK(t9r   c           	       > [        5       nU R                  5        H_  u  pg[        U[        5      (       a.  Uc  T
" UUUUS9(       a  XuU'   M1  M3  U" U5      (       a  XuU'   MF  MH  T	" UUUUUS9nU(       d  M[  XU'   Ma     U$ )N)r@   r0   r>   r@   r0   r>   function)r   itemsr    r!   )bunchr@   r0   r>   rJ   newr   valuefiltered_filter_bunchrF   s            r   rP   #Bunch.filter.<locals>._filter_bunch   s    'C#kkm
e\22'$!$+!%+9	 (-H $E??',H +  - '!'5!) H  x#+C/ ,2 Jr   rI   r7   )r   r@   r0   r>   rJ   rP   rF   s        @@r   filterBunch.filter~   s,    D	2	: )
 	
r   c                ,   U R                  5       R                  5        VVs0 s H)  u  p#UR                  [        5      R	                  5       U_M+     nnnUR                  [        5      R	                  5       nXT;   a  XE   $ [        SU S35      es  snnf )a  Return :class:`TileProvider` based on the name query

Returns a matching :class:`TileProvider` from the :class:`Bunch` if the ``name``
contains the same letters in the same order as the provider's name irrespective
of the letter case, spaces, dashes and other characters.
See examples for details.

Parameters
----------
name : str
    Name of the tile provider. Formatting does not matter.

Returns
-------
match: TileProvider

Examples
--------
>>> import xyzservices.providers as xyz

All these queries return the same ``CartoDB.Positron`` TileProvider:

>>> xyz.query_name("CartoDB Positron")
>>> xyz.query_name("cartodbpositron")
>>> xyz.query_name("cartodb-positron")
>>> xyz.query_name("carto db/positron")
>>> xyz.query_name("CARTO_DB_POSITRON")
>>> xyz.query_name("CartoDB.Positron")

z*No matching provider found for the query 'z'.)r8   rK   	translateQUERY_NAME_TRANSLATIONr<   
ValueError)r   r0   krC   xyz_flat_lower
name_cleans         r   
query_nameBunch.query_name   s    B ,,.
. KK./557:. 	 
 ^^$:;AAC
'!--EdV2NOO
s   0Br7   F)returndict)NNNN)
r@   
str | Noner0   r`   r>   bool | NonerJ   zCallable[[TileProvider], bool]r^   r   r0   r"   r^   r!   )__name__
__module____qualname____firstlineno____doc__r   r   r%   r8   rR   r[   __static_attributes__r7   r   r   r   r      sm    4/$L"L #&*37~
~
 ~
 $	~

 1~
 
~
@'Pr   r   c                     ^  \ rS rSrSrU 4S jrSS jrSS jr     S           SS jjrSS jr	\
S 5       rSS	 jr\SS
 j5       rSrU =r$ )r!   i(  at  
A dict with attribute-access and that
can be called to update keys


Examples
--------

You can create custom :class:`TileProvider` by passing your attributes to the object
as it would have been a ``dict()``. It is required to always specify ``name``,
``url``, and ``attribution``.

>>> public_provider = TileProvider(
...     name="My public tiles",
...     url="https://myserver.com/tiles/{z}/{x}/{y}.png",
...     attribution="(C) xyzservices",
... )

Alternatively, you can create it from a dictionary of attributes. When specifying a
placeholder for the access token, please use the ``"<insert your access token
here>"`` string to ensure that :meth:`~xyzservices.TileProvider.requires_token`
method works properly.

>>> private_provider = TileProvider(
...    {
...        "url": "https://myserver.com/tiles/{z}/{x}/{y}.png?apikey={accessToken}",
...        "attribution": "(C) xyzservices",
...        "accessToken": "<insert your access token here>",
...        "name": "my_private_provider",
...    }
... )

It is customary to include ``html_attribution`` attribute containing HTML string as
``'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>
contributors'`` alongisde a plain-text ``attribution``.

You can then fetch all information as attributes:

>>> public_provider.url
'https://myserver.com/tiles/{z}/{x}/{y}.png'

>>> public_provider.attribution
'(C) xyzservices'

To ensure you will be able to use the tiles, you can check if the
:class:`TileProvider` requires a token or API key.

>>> public_provider.requires_token()
False
>>> private_provider.requires_token()
True

You can also generate URL in the required format with or without placeholders:

>>> public_provider.build_url()
'https://myserver.com/tiles/{z}/{x}/{y}.png'
>>> private_provider.build_url(x=12, y=21, z=11, accessToken="my_token")
'https://myserver.com/tiles/11/12/21.png?access_token=my_token'

c                   > [         TU ]  " U0 UD6  / nS H)  nX@R                  5       ;  d  M  UR                  U5        M+     [	        U5      S:  a   SSR                  U5       S3n[        U5      eg )N)r0   urlattributionr   zyThe attributes `name`, `url`, and `attribution` are required to initialise a `TileProvider`. Please provide values for: `z`, ``)super__init__r   r=   r'   joinr   )r   argskwargsmissingelmsg	__class__s         r   ro   TileProvider.__init__f  s~    $)&)0B$r" 1 w<! KK(),  !%% r   c                >    [        U 5      nUR                  U5        U$ r   )r!   update)r   rr   rM   s      r   __call__TileProvider.__call__u  s    4 

6
r   c                    [        U 5      nU$ r   )r!   )r   rM   s     r   copyTileProvider.copyz  s    4 
r   c           	        U R                  5       nUc  SnUc  SnUc  SnUR                  U5        UR                  5       (       a  [        S5      eUR	                  S5      nU(       a  Un	UR	                  SS5        OUR	                  SS5      n	U(       a  UR	                  S	S
5      n
U
S   nOSnUR
                  " SXX;U	S.UD6$ )a  
Build the URL of tiles from the :class:`TileProvider` object

Can return URL with placeholders or the final tile URL.

Parameters
----------

x, y, z : int (optional)
    tile number
scale_factor : str (optional)
    Scale factor (where supported). For example, you can get double resolution
    (512 x 512) instead of standard one (256 x 256) with ``"@2x"``. If you want
    to keep a placeholder, pass `"{r}"`.
fill_subdomain : bool (optional, default True)
    Fill subdomain placeholder with the first available subdomain. If False, the
    URL will contain ``{s}`` placeholder for subdomain.

**kwargs
    Other potential attributes updating the :class:`TileProvider`.

Returns
-------

url : str
    Formatted URL

Examples
--------
>>> import xyzservices.providers as xyz

>>> xyz.CartoDB.DarkMatter.build_url()
'https://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png'

>>> xyz.CartoDB.DarkMatter.build_url(x=9, y=11, z=5)
'https://a.basemaps.cartocdn.com/dark_all/5/9/11.png'

>>> xyz.CartoDB.DarkMatter.build_url(x=9, y=11, z=5, scale_factor="@2x")
'https://a.basemaps.cartocdn.com/dark_all/5/9/11@2x.png'

>>> xyz.MapBox.build_url(accessToken="my_token")
'https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=my_token'

Nz{x}z{y}z{z}zToken is required for this provider, but not provided. You can either update TileProvider or pass respective keywords to build_url().rk   rr   
subdomainsabcr   z{s})xyzsr   r7   )r}   ry   r>   rW   popformat)r   r   r   r   scale_factorfill_subdomainrr   r2   rk   r   r   r   s               r   	build_urlTileProvider.build_url~  s    j 99;9A9A9A""$$"  ll5!ALLd#S"%A!lE:J1AAzz>Aa>X>>r   c                    U R                  5        H5  u  p[        U[        5      (       d  M  SU;   d  M$  XR                  ;   d  M5    g   g)a  
Returns ``True`` if the TileProvider requires access token to fetch tiles.

The token attribute name vary and some :class:`TileProvider` objects may require
more than one token (e.g. ``HERE``). The information is deduced from the
presence of `'<insert your...'` string in one or more of attributes. When
specifying a placeholder for the access token, please use the ``"<insert your
access token here>"`` string to ensure that
:meth:`~xyzservices.TileProvider.requires_token` method works properly.

Returns
-------
bool

Examples
--------
>>> import xyzservices.providers as xyz
>>> xyz.MapBox.requires_token()
True

>>> xyz.CartoDB.Positron
False

We can specify this API key by calling the object or overriding the attribute.
Overriding the attribute will alter existing object:

>>> xyz.OpenWeatherMap.Clouds["apiKey"] = "my-private-api-key"

Calling the object will return a copy:

>>> xyz.OpenWeatherMap.Clouds(apiKey="my-private-api-key")


z<insert yourTF)rK   r    r"   rk   )r   r   vals      r   r>   TileProvider.requires_token  s;    H 

HC#s###(=#/ % r   c                "    SU ;   a  U S   $ U S   $ )Nhtml_attributionrl   r7   r   s    r   r   TileProvider.html_attribution  s!    %*++M""r   c                    SnU R                  5        H  u  p4US:w  d  M  USU SU S3-  nM     U(       a  SO	S[         S3nSU S	U R                   S
U S3nU$ )Nr   r0   z
<dt><span>z</span></dt><dd>z</dd>r   r   r   z
            <div class="xyz-wrap">
                <div class="xyz-header">
                    <div class="xyz-obj">xyzservices.TileProvider</div>
                    <div class="xyz-name">z</div>
                </div>
                <div class="xyz-details">
                    <dl class="xyz-attrs">
                        z\
                    </dl>
                </div>
            </div>
        </div>
        )rK   r&   r0   )r   r   provider_infor   r   r+   r,   s          r   r%   TileProvider._repr_html_  s    

HCf}:cU2B3%u!MM % GI;h"?		 + ,099+ 6 ' (	" r   c           	        Sn[         R                  " [        R                  R	                  U S[        U5       S35      5      nU H  nUS   U:X  d  M    O   [        SU S35      eUS   n[         R                  " [        R                  R	                  U SU 35      5      nU " US   US	   UR                  S
5      UR                  S5      UR                  S5      S9$ )aW  
Creates a :class:`TileProvider` object based on the definition from
the `Quick Map Services <https://qms.nextgis.com/>`__ open catalog.

Parameters
----------
name : str
    Service name

Returns
-------
:class:`TileProvider`

Examples
--------
>>> from xyzservices.lib import TileProvider
>>> provider = TileProvider.from_qms("OpenTopoMap")
z*https://qms.nextgis.com/api/v1/geoservicesz	/?search=z	&type=tmsr0   z	Service 'z' not found.id/rk   z_minz_maxcopyright_text)r0   rk   min_zoommax_zoomrl   )jsonloadurllibrequesturlopenr   rW   get)clsr0   qms_api_urlservicesservice
service_idservice_detailss          r   from_qmsTileProvider.from_qms  s    ( C99NN""k])E$K=	#RS
  Gv$&   yl;<<T]
))NN""k]!J<#@A
  (&$((1$((1'++,<=
 	
r   r7   )r^   r!   )NNNNT)r   int | str | Noner   r   r   r   r   r`   r   ra   r^   r"   )r^   boolr]   rb   )rc   rd   re   rf   rg   ro   rz   r}   r   r>   propertyr   r%   classmethodr   rh   __classcell__)rv   s   @r   r!   r!   (  s    ;z&
 #""#'&*U?U? U? 	U?
 !U? $U? 
U?n'R # #
4 *
 *
r   r!   c                    [         R                  " U 5      n[        5       nU HE  nX   nSU;   a  [        U5      X#'   M  [        U Vs0 s H  oU[        XE   5      _M     sn5      X#'   MG     U$ s  snf )Nrk   )r   loadsr   r!   )fdata	providersprovider_namer2   is         r   
_load_jsonr   L  sv    ::a=DI&H'3H'=I$ (-7?@x!L--x@(I$   As   A.
u8  
/* CSS stylesheet for displaying xyzservices objects in Jupyter.*/
.xyz-wrap {
    --xyz-border-color: var(--jp-border-color2, #ddd);
    --xyz-font-color2: var(--jp-content-font-color2, rgba(128, 128, 128, 1));
    --xyz-background-color-white: var(--jp-layout-color1, white);
    --xyz-background-color: var(--jp-layout-color2, rgba(128, 128, 128, 0.1));
}

html[theme=dark] .xyz-wrap,
body.vscode-dark .xyz-wrap,
body.vscode-high-contrast .xyz-wrap {
    --xyz-border-color: #222;
    --xyz-font-color2: rgba(255, 255, 255, 0.54);
    --xyz-background-color-white: rgba(255, 255, 255, 1);
    --xyz-background-color: rgba(255, 255, 255, 0.05);

}

.xyz-header {
    padding-top: 6px;
    padding-bottom: 6px;
    margin-bottom: 4px;
    border-bottom: solid 1px var(--xyz-border-color);
}

.xyz-header>div {
    display: inline;
    margin-top: 0;
    margin-bottom: 0;
}

.xyz-obj,
.xyz-name {
    margin-left: 2px;
    margin-right: 10px;
}

.xyz-obj {
    color: var(--xyz-font-color2);
}

.xyz-attrs {
    grid-column: 1 / -1;
}

dl.xyz-attrs {
    padding: 0 5px 0 5px;
    margin: 0;
    display: grid;
    grid-template-columns: 135px auto;
    background-color: var(--xyz-background-color);
}

.xyz-attrs dt,
dd {
    padding: 0;
    margin: 0;
    float: left;
    padding-right: 10px;
    width: auto;
}

.xyz-attrs dt {
    font-weight: normal;
    grid-column: 1;
}

.xyz-attrs dd {
    grid-column: 2;
    white-space: pre-wrap;
    word-break: break-all;
}

.xyz-details ul>li>label>span {
    color: var(--xyz-font-color2);
    padding-left: 10px;
}

.xyz-inside {
    display: none;
}

.xyz-checkbox:checked~.xyz-inside {
    display: contents;
}

.xyz-collapsible li>input {
    display: none;
}

.xyz-collapsible>li>label {
    cursor: pointer;
}

.xyz-collapsible>li>label:hover {
    color: var(--xyz-font-color2);
}

ul.xyz-collapsible {
    list-style: none!important;
    padding-left: 20px!important;
}

.xyz-checkbox+label:before {
    content: '►';
    font-size: 11px;
}

.xyz-checkbox:checked+label:before {
    content: '▼';
}

.xyz-wrap {
    margin-bottom: 10px;
}
)rg   
__future__r   r   urllib.requestr   r#   typingr   urllib.parser   r"   	maketransrV   r_   r   r!   r   r&   )r   s   0r   <module>r      sr    #     x'@x!2x'@A UPD UPpa
5 a
H	&t	e (As   A