Repository: banesullivan/localtileserver (python)

Issue:
could BoundTileLayer be declared outside of the function ? 
In one of my application, I'm scrolling in the layers displayed on my map and performed different operations depeding on where there from. The only way I can make the differents between something comming from localtileserver and another TileLayer is the type. In https://github.com/banesullivan/localtileserver/blob/165de5dc63b45689a72e22035f1fa2135eb93b71/localtileserver/widgets.py#L100 you are using the BoundTileLayer for your layer. it's quite hoard to reach for a simple `isinstance` test. would it be possible to set it as a standalone class in `localtileserver.widget` ? 

Pull request description:
add LocalTileServerLayerMixin class
Resolve #104 

Patch:
diff --git a/localtileserver/__init__.py b/localtileserver/__init__.py
index bee6cfb..1d98361 100644
--- a/localtileserver/__init__.py
+++ b/localtileserver/__init__.py
@@ -4,6 +4,7 @@ from localtileserver.client import RemoteTileClient, TileClient, get_or_create_t
 from localtileserver.report import Report
 from localtileserver.tileserver.utilities import get_cache_dir, make_vsi, purge_cache
 from localtileserver.widgets import (
+    LocalTileServerLayerMixin,
     get_folium_tile_layer,
     get_leaflet_roi_controls,
     get_leaflet_tile_layer,
diff --git a/localtileserver/widgets.py b/localtileserver/widgets.py
index 5564c62..0f947c9 100644
--- a/localtileserver/widgets.py
+++ b/localtileserver/widgets.py
@@ -14,6 +14,12 @@ logger = logging.getLogger(__name__)
 DEFAULT_ATTRIBUTION = "Raster file served by <a href='https://github.com/banesullivan/localtileserver' target='_blank'>localtileserver</a>."
 
 
+class LocalTileServerLayerMixin:
+    """Mixin class for tile layers using localtileserver."""
+
+    pass
+
+
 def get_leaflet_tile_layer(
     source: Union[pathlib.Path, str, TileClient, DatasetReaderBase],
     port: Union[int, str] = "default",
@@ -97,7 +103,7 @@ def get_leaflet_tile_layer(
     except ImportError as e:  # pragma: no cover
         raise ImportError(f"Please install `ipyleaflet`: {e}")
 
-    class BoundTileLayer(TileLayer):
+    class BoundTileLayer(TileLayer, LocalTileServerLayerMixin):
         # https://github.com/jupyter-widgets/ipyleaflet/issues/888
         # https://github.com/ipython/traitlets/issues/626#issuecomment-699957829
         bounds = Union((Tuple(),), default_value=None, allow_none=True).tag(sync=True, o=True)
@@ -302,6 +308,10 @@ def get_folium_tile_layer(
         from folium import TileLayer
     except ImportError as e:  # pragma: no cover
         raise ImportError(f"Please install `folium`: {e}")
+
+    class FoliumTileLayer(TileLayer, LocalTileServerLayerMixin):
+        pass
+
     source, created = get_or_create_tile_client(
         source, port=port, debug=debug, default_projection=default_projection
     )
@@ -322,7 +332,7 @@ def get_folium_tile_layer(
         attr = DEFAULT_ATTRIBUTION
     if projection is None or (not projection and source.default_projection is None):
         kwargs.setdefault("crs", "Simple")
-    tile_layer = TileLayer(tiles=url, attr=attr, **kwargs)
+    tile_layer = FoliumTileLayer(tiles=url, attr=attr, **kwargs)
     if created:
         # HACK: Prevent the client from being garbage collected
         tile_layer.tile_server = source
diff --git a/setup.py b/setup.py
index 4ca17ad..1ef5ffb 100644
--- a/setup.py
+++ b/setup.py
@@ -49,7 +49,7 @@ setup(
         "requests",
         "server-thread",
         "scooby",
-        "werkzeug<2.2"
+        "werkzeug<2.2",
     ],
     extras_require={
         "colormaps": ["matplotlib", "colorcet", "cmocean"],


Test patch:
diff --git a/tests/test_folium.py b/tests/test_folium.py
index 1a20e3e..ffc5c5a 100644
--- a/tests/test_folium.py
+++ b/tests/test_folium.py
@@ -1,6 +1,6 @@
 import pytest
 
-from localtileserver import get_folium_tile_layer
+from localtileserver import LocalTileServerLayerMixin, get_folium_tile_layer
 from localtileserver.client import DEMO_REMOTE_TILE_SERVER, RemoteTileClient
 
 skip_folium = False
@@ -20,12 +20,14 @@ def test_leaflet_tile_layer(bahamas):
         bahamas, band=1, palette="matplotlib.Viridis_20", vmin=0, vmax=255, nodata=0
     )
     assert isinstance(layer, TileLayer)
+    assert isinstance(layer, LocalTileServerLayerMixin)
 
 
 @pytest.mark.skipif(skip_folium, reason="folium not installed")
 def test_folium_tile_layer_from_path(bahamas_file):
     layer = get_folium_tile_layer(bahamas_file)
     assert isinstance(layer, TileLayer)
+    assert isinstance(layer, LocalTileServerLayerMixin)
 
 
 def test_folium_with_remote_client(remote_file_url):
diff --git a/tests/test_leaflet.py b/tests/test_leaflet.py
index 8133c91..916d0fb 100644
--- a/tests/test_leaflet.py
+++ b/tests/test_leaflet.py
@@ -1,6 +1,10 @@
 import pytest
 
-from localtileserver import get_leaflet_roi_controls, get_leaflet_tile_layer
+from localtileserver import (
+    LocalTileServerLayerMixin,
+    get_leaflet_roi_controls,
+    get_leaflet_tile_layer,
+)
 
 skip_leaflet = False
 try:
@@ -19,12 +23,14 @@ def test_leaflet_tile_layer(bahamas):
         bahamas, band=1, palette="matplotlib.Viridis_20", vmin=0, vmax=255, nodata=0
     )
     assert isinstance(layer, TileLayer)
+    assert isinstance(layer, LocalTileServerLayerMixin)
 
 
 @pytest.mark.skipif(skip_leaflet, reason="ipyleaflet not installed")
 def test_leaflet_tile_layer_from_path(bahamas_file):
     layer = get_leaflet_tile_layer(bahamas_file)
     assert isinstance(layer, TileLayer)
+    assert isinstance(layer, LocalTileServerLayerMixin)
 
 
 @pytest.mark.skipif(skip_leaflet, reason="ipyleaflet not installed")