diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml
new file mode 100644
index 0000000..dd88038
--- /dev/null
+++ b/.github/workflows/flake8.yml
@@ -0,0 +1,18 @@
+name: flake8 Lint
+
+on: [push, pull_request]
+
+jobs:
+ flake8-lint:
+ runs-on: ubuntu-latest
+ name: Lint with flake8
+ steps:
+ - uses: actions/checkout@v1
+ - uses: ricardochaves/python-lint@v1.3.0
+ with:
+ use-pylint: false
+ use-pycodestyle: false
+ use-flake8: true
+ use-black: false
+ use-mypy: false
+ use-isort: false
diff --git a/.github/workflows/python-test-suite.yml b/.github/workflows/python-test-suite.yml
index f9952d4..51fb73d 100644
--- a/.github/workflows/python-test-suite.yml
+++ b/.github/workflows/python-test-suite.yml
@@ -28,13 +28,6 @@ jobs:
- name: Install Mapshader code
run: |
$CONDA/bin/pip install -e .
- - name: Lint with flake8
- run: |
- # $CONDA/bin/conda install flake8
- # stop the build if there are Python syntax errors or undefined names
- # $CONDA/bin/flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
- # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
- # $CONDA/bin/flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
$CONDA/bin/pip install pytest
diff --git a/conda.recipe/run_test.py b/conda.recipe/run_test.py
index 7e342f8..1042d3d 100644
--- a/conda.recipe/run_test.py
+++ b/conda.recipe/run_test.py
@@ -1 +1,4 @@
-import mapshader;mapshader.test()
+import mapshader
+
+
+mapshader.test()
diff --git a/mapshader/__init__.py b/mapshader/__init__.py
index 049f32d..5546248 100644
--- a/mapshader/__init__.py
+++ b/mapshader/__init__.py
@@ -32,5 +32,10 @@ def hello(services=None):
print('\tServices', file=sys.stdout)
print('\t--------\n', file=sys.stdout)
for s in services:
- service_msg = f'\t > {s.name} - {s.service_type} - {s.source.geometry_type} - {s.source.description}'
+ service_msg = '\t > {0} - {1} - {2} - {3}'.format(
+ s.name,
+ s.service_type,
+ s.source.geometry_type,
+ s.source.description
+ )
print(service_msg, file=sys.stdout)
diff --git a/mapshader/commands/__init__.py b/mapshader/commands/__init__.py
new file mode 100644
index 0000000..214d9a4
--- /dev/null
+++ b/mapshader/commands/__init__.py
@@ -0,0 +1,17 @@
+from pkg_resources import iter_entry_points as entry_points
+
+import click
+from click_plugins import with_plugins
+
+
+@with_plugins(cmd for cmd in list(entry_points('mapshader.commands')))
+@click.group(context_settings=dict(help_option_names=['-h', '--help']))
+def main(args=None):
+ '''
+ mapshader command line interface.
+ '''
+ pass
+
+
+if __name__ == '__main__':
+ main()
diff --git a/mapshader/commands/examples.py b/mapshader/commands/examples.py
new file mode 100644
index 0000000..a27c3ef
--- /dev/null
+++ b/mapshader/commands/examples.py
@@ -0,0 +1,31 @@
+import click
+import pyct.cmd
+
+
+@click.command(
+ context_settings=dict(help_option_names=['-h', '--help']),
+ help='Copy examples and fetch data to the supplied path.',
+ short_help='Copy examples and fetch data to the supplied path.',
+)
+@click.option(
+ '--path',
+ 'path',
+ default='.',
+ show_default=True,
+ help='Relative path to copy the examples.',
+)
+@click.option(
+ '--force',
+ 'force',
+ is_flag=True,
+ help='Force overwrite examples if they already exist.',
+)
+def examples(path, force):
+ try:
+ pyct.cmd.substitute_main(
+ 'mapshader',
+ cmds='examples',
+ args=dict(path=path, fornce=force),
+ )
+ except ValueError as e:
+ raise click.BadArgumentUsage(e)
diff --git a/mapshader/commands/tif_to_netcdf.py b/mapshader/commands/tif_to_netcdf.py
new file mode 100644
index 0000000..5bec56c
--- /dev/null
+++ b/mapshader/commands/tif_to_netcdf.py
@@ -0,0 +1,149 @@
+from os import path
+import sys
+
+import click
+import xarray as xr
+
+from mapshader.transforms import cast
+from mapshader.transforms import flip_coords
+from mapshader.transforms import orient_array
+from mapshader.transforms import reproject_raster
+from mapshader.transforms import squeeze
+
+
+@click.command(
+ no_args_is_help=True,
+ context_settings=dict(help_option_names=['-h', '--help']),
+ short_help='Convert GeoTIFF raster file format into a NetCDF file.',
+ help=(
+ 'Convert GeoTIFF raster file format into a NetCDF file '
+ 'given the `FILEPATH` relative path.'
+ ),
+)
+@click.argument(
+ 'filepath',
+ type=str,
+ required=True,
+)
+@click.option(
+ '--x',
+ type=str,
+ default='x',
+ show_default=True,
+ help='The x dimension name.',
+)
+@click.option(
+ '--y',
+ type=str,
+ default='y',
+ show_default=True,
+ help='The y dimension name.',
+)
+@click.option(
+ '--chunks',
+ type=tuple,
+ default=(512, 512),
+ show_default=True,
+ help='Coerce into dask arrays with the given chunks.',
+)
+@click.option(
+ '--data_variable',
+ type=str,
+ default='data',
+ show_default=True,
+ help='The data variable name.',
+)
+@click.option(
+ '--fill_na',
+ type=int,
+ default=-9999,
+ show_default=True,
+ help='Fill NaN values with the given value.',
+)
+@click.option(
+ '-c',
+ '--cast',
+ 'dtype',
+ default='int16',
+ show_default=True,
+ help='Cast the data to the given type.',
+)
+@click.option(
+ '-r',
+ '--reproject',
+ 'crs',
+ type=int,
+ default=3857,
+ show_default=True,
+ help='Reproject the data to the given CRS.',
+)
+def tif_to_netcdf(
+ filepath,
+ x,
+ y,
+ chunks,
+ data_variable,
+ fill_na,
+ dtype,
+ crs,
+):
+ '''
+ Convert GeoTIFF raster file format into a NetCDF file given the
+ `FILEPATH` relative path.
+
+ Parameters
+ ----------
+ filepath : str
+ GeoTIFF raster file relative path.
+ x : str
+ The x dimension name.
+ y : str
+ The y dimension name.
+ chunks : tuple of int
+ The dask array chunk size for the x and y dimension.
+ data_variable : str
+ The data variable name.
+ fill_na : int or float
+ Fill NaN values with the given value.
+ dtype : str
+ Cast the data to the given type.
+ crs : int
+ Reproject the data to the given CRS.
+ '''
+ input_file = path.abspath(path.expanduser(filepath))
+ output_file = input_file.replace('.tif', '.nc')
+
+ print(
+ 'Converting {0} from GeoTIFF to NetCDF file'.format(input_file),
+ file=sys.stdout,
+ )
+
+ arr = xr.open_rasterio(input_file)
+
+ # Check if the given dimensions exist
+ for dimension in (x, y):
+ if dimension not in arr.dims:
+ raise click.BadParameter(
+ "The dimension name {} doesn't exist.".format(dimension)
+ )
+
+ arr = squeeze(arr, [d for d in arr.dims if d != x and d != y])
+ arr = cast(arr, dtype=dtype)
+ arr = orient_array(arr)
+ arr = flip_coords(arr, dim=y)
+ arr = reproject_raster(arr, epsg=crs)
+
+ dataset = xr.Dataset(
+ data_vars={data_variable: (['y', 'x'], arr.chunk(chunks))},
+ coords={'x': arr.coords[x], 'y': arr.coords[y]},
+ )
+ dataset.attrs = dict(name=data_variable)
+ dataset.to_netcdf(
+ path=output_file,
+ encoding={data_variable: {'_FillValue': fill_na}},
+ )
+
+ print(
+ 'Conversion complete: {0}'.format(output_file),
+ file=sys.stdout,
+ )
diff --git a/mapshader/core.py b/mapshader/core.py
index 75d8074..cc60d09 100644
--- a/mapshader/core.py
+++ b/mapshader/core.py
@@ -278,7 +278,7 @@ def to_raster(source: MapSource,
return create_agg(source, xmin, ymin, xmax, ymax, None, None, None, height, width)
-def render_map(source: MapSource,
+def render_map(source: MapSource, # noqa: C901
xmin: float = None, ymin: float = None,
xmax: float = None, ymax: float = None,
x: float = None, y: float = None,
diff --git a/mapshader/flask_app.py b/mapshader/flask_app.py
index 5af5ca6..c7a8432 100644
--- a/mapshader/flask_app.py
+++ b/mapshader/flask_app.py
@@ -74,12 +74,6 @@ def flask_to_geojson(source: MapSource):
if not source.is_loaded:
source.load()
- q = request.args.get('q')
- limit = request.args.get('limit')
- offset = request.args.get('offset')
- simplify = request.args.get('simplify')
- bbox = request.args.get('bbox')
-
resp = render_geojson(source)
return resp
@@ -128,58 +122,89 @@ def service_page(service: MapService):
plot = build_previewer(service)
script, div = components(dict(preview=plot))
- template = Template('''
-
-
-
-
- {{service.name}}
- {{ resources }}
- {{ script }}
-
-
-
- {{ psutils_html }}
-
-
-
- {% for key in div.keys() %}
- {{ div[key] }}
- {% endfor %}
-
-
-
-
-
- ''')
+ template = Template(
+ '''
+
+
+
+
+
+ {{service.name}}
+ {{ resources }}
+ {{ script }}
+
+
+
+ {{ psutils_html }}
+
+
+
+ {% for key in div.keys() %}
+ {{ div[key] }}
+ {% endfor %}
+
+
+
+
+
+ '''
+ )
resources = INLINE.render()
html = template.render(resources=resources,
diff --git a/mapshader/io.py b/mapshader/io.py
index 92ae6d3..de2af9b 100644
--- a/mapshader/io.py
+++ b/mapshader/io.py
@@ -1,12 +1,8 @@
-import rioxarray
-import xarray as xr
-import datashader as ds
-import geopandas as gpd
-import numpy as np
-from affine import Affine
-
from os.path import expanduser
+import geopandas as gpd
+import numpy as np
+import xarray as xr
def load_raster(file_path, xmin=None, ymin=None,
diff --git a/mapshader/mercator.py b/mapshader/mercator.py
index 0f2e7b4..685a7f0 100644
--- a/mapshader/mercator.py
+++ b/mapshader/mercator.py
@@ -54,14 +54,12 @@ def to_ogc_tile_metadata(self, output_file_path):
'''
pass
-
def to_esri_tile_metadata(self, output_file_path):
'''
Create ESRI tile metadata JSON
'''
pass
-
def is_valid_tile(self, x, y, z):
if x < 0 or x >= math.pow(2, z):
@@ -72,18 +70,15 @@ def is_valid_tile(self, x, y, z):
return True
-
# TODO ngjit?
def _get_resolution(self, z):
return self.initial_resolution / (2 ** z)
-
def get_resolution_by_extent(self, extent, height, width):
x_rs = (extent[2] - extent[0]) / width
y_rs = (extent[3] - extent[1]) / height
return [x_rs, y_rs]
-
def get_level_by_extent(self, extent, height, width):
x_rs = (extent[2] - extent[0]) / width
y_rs = (extent[3] - extent[1]) / height
@@ -100,21 +95,18 @@ def get_level_by_extent(self, extent, height, width):
i += 1
return (i-1)
-
def pixels_to_meters(self, px, py, level):
res = self._get_resolution(level)
mx = (px * res) - self.x_origin_offset
my = (py * res) - self.y_origin_offset
return (mx, my)
-
def meters_to_pixels(self, mx, my, level):
res = self._get_resolution(level)
px = (mx + self.x_origin_offset) / res
py = (my + self.y_origin_offset) / res
return (px, py)
-
def pixels_to_tile(self, px, py, level):
tx = math.ceil(px / self.tile_size)
tx = tx if tx == 0 else tx - 1
@@ -122,19 +114,15 @@ def pixels_to_tile(self, px, py, level):
# convert from TMS y coordinate
return (int(tx), invert_y_tile(int(ty), level))
-
def pixels_to_raster(self, px, py, level):
map_size = self.tile_size << level
return (px, map_size - py)
-
def meters_to_tile(self, mx, my, level):
px, py = self.meters_to_pixels(mx, my, level)
return self.pixels_to_tile(px, py, level)
-
def get_tiles_by_extent(self, extent, level):
-
# unpack extent and convert to tile coordinates
xmin, ymin, xmax, ymax = extent
# note y coordinates are reversed since they are in opposite direction to meters
@@ -151,10 +139,12 @@ def get_tiles_by_extent(self, extent, level):
return tiles
-
def get_tile_meters(self, tx, ty, level):
- ty = invert_y_tile(ty, level) # convert to TMS for conversion to meters
+ ty = invert_y_tile(ty, level) # convert to TMS for conversion to meters
xmin, ymin = self.pixels_to_meters(tx * self.tile_size, ty * self.tile_size, level)
- xmax, ymax = self.pixels_to_meters((tx + 1) * self.tile_size, (ty + 1) * self.tile_size, level)
+ xmax, ymax = self.pixels_to_meters(
+ (tx + 1) * self.tile_size,
+ (ty + 1) * self.tile_size,
+ level,
+ )
return (xmin, ymin, xmax, ymax)
-
diff --git a/mapshader/sources.py b/mapshader/sources.py
index 10c90c1..a8d74fe 100644
--- a/mapshader/sources.py
+++ b/mapshader/sources.py
@@ -16,7 +16,7 @@
class MapSource(object):
- def __init__(self,
+ def __init__(self, # noqa: C901
name=None,
description=None,
filepath=None,
diff --git a/mapshader/tests/fixtures/shade.nc b/mapshader/tests/fixtures/shade.nc
new file mode 100644
index 0000000..5d703eb
Binary files /dev/null and b/mapshader/tests/fixtures/shade.nc differ
diff --git a/mapshader/tests/fixtures/shade.tif b/mapshader/tests/fixtures/shade.tif
new file mode 100644
index 0000000..9ea0f3f
Binary files /dev/null and b/mapshader/tests/fixtures/shade.tif differ
diff --git a/mapshader/tests/test_tif_to_netcdf.py b/mapshader/tests/test_tif_to_netcdf.py
new file mode 100644
index 0000000..8b2a34c
--- /dev/null
+++ b/mapshader/tests/test_tif_to_netcdf.py
@@ -0,0 +1,81 @@
+import filecmp
+from os import path
+import shutil
+
+from click import BadParameter
+from click.testing import CliRunner
+from rasterio.errors import RasterioIOError
+
+from mapshader.commands.tif_to_netcdf import tif_to_netcdf
+from mapshader.tests.data import FIXTURES_DIR
+
+
+def test_invalid_y_dimension_name():
+ runner = CliRunner()
+ input_file = path.join(FIXTURES_DIR, 'shade.tif')
+
+ result = runner.invoke(
+ tif_to_netcdf, [input_file, '--x', '1'], standalone_mode=False
+ )
+ assert isinstance(result.exception, BadParameter)
+
+
+def test_invalid_x_dimension_name():
+ runner = CliRunner()
+ input_file = path.join(FIXTURES_DIR, 'shade.tif')
+
+ result = runner.invoke(
+ tif_to_netcdf, [input_file, '--x', '1'], standalone_mode=False
+ )
+ assert isinstance(result.exception, BadParameter)
+
+
+def test_invalid_input_file():
+ runner = CliRunner()
+ input_file = path.join(FIXTURES_DIR, 'counties_3857.gpkg')
+
+ result = runner.invoke(tif_to_netcdf, [input_file], standalone_mode=False)
+ assert isinstance(result.exception, RasterioIOError)
+
+
+def test_invalid_input_file_path():
+ runner = CliRunner()
+ input_file = path.join(FIXTURES_DIR, 'nd.tif')
+
+ result = runner.invoke(tif_to_netcdf, [input_file], standalone_mode=False)
+ assert isinstance(result.exception, RasterioIOError)
+
+
+def test_invalid_dtype_cast():
+ runner = CliRunner()
+ input_file = path.join(FIXTURES_DIR, 'shade.tif')
+
+ result = runner.invoke(
+ tif_to_netcdf, [input_file, '--cast', 'int2'], standalone_mode=False
+ )
+ assert isinstance(result.exception, TypeError)
+
+
+def test_invalid_reprojection():
+ runner = CliRunner()
+ input_file = path.join(FIXTURES_DIR, 'shade.tif')
+
+ result = runner.invoke(
+ tif_to_netcdf, [input_file, '--reproject', '123'], standalone_mode=False
+ )
+ assert isinstance(result.exception, ValueError)
+
+
+def test_valid_conversion(tmpdir):
+ runner = CliRunner()
+
+ input_filename = 'shade.tif'
+ output_filename = 'shade.nc'
+
+ input_filepath = tmpdir.join(input_filename).strpath
+ output_filepath = tmpdir.join(output_filename).strpath
+ expected_output_filepath = path.join(FIXTURES_DIR, output_filename)
+
+ shutil.copy2(path.join(FIXTURES_DIR, input_filename), input_filepath)
+ runner.invoke(tif_to_netcdf, [input_filepath], standalone_mode=False)
+ assert filecmp.cmp(output_filepath, expected_output_filepath)
diff --git a/mapshader/transforms.py b/mapshader/transforms.py
index e153895..6b15ab5 100644
--- a/mapshader/transforms.py
+++ b/mapshader/transforms.py
@@ -13,7 +13,10 @@
wgs84_proj_str = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'
-us_national_equal_area_str = '+proj=laea +lat_0=45 +lon_0=-100 +x_0=0 +y_0=0 +a=6370997 +b=6370997 +units=m +no_defs'
+us_national_equal_area_str = (
+ '+proj=laea +lat_0=45 +lon_0=-100 +x_0=0 +y_0=0 +a=6370997 '
+ '+b=6370997 +units=m +no_defs'
+)
projections = {
3857: wb_proj_str,
diff --git a/mapshader/utils.py b/mapshader/utils.py
index e9e4936..7f69c57 100644
--- a/mapshader/utils.py
+++ b/mapshader/utils.py
@@ -40,7 +40,7 @@ def find_and_set_categoricals(df):
def psutil_fetching():
# CPU logs
- cpu_usage_percentage = psutil.cpu_percent(interval = 1)
+ cpu_usage_percentage = psutil.cpu_percent(interval=1)
cpu_number_logical = psutil.cpu_count()
cpu_number_physical = psutil.cpu_count(logical=False)
@@ -49,16 +49,16 @@ def psutil_fetching():
cpu_per_cpu_percentage = psutil.cpu_percent(interval=1, percpu=True)
# Disks
- disk_usage = psutil.disk_usage("/") # Root disk usage
+ disk_usage = psutil.disk_usage("/") # Root disk usage
log = {
'cpu':
{
- 'cpu_usage_percentage': cpu_usage_percentage,
- 'cpu_number_logical': cpu_number_logical,
- 'cpu_number_physical': cpu_number_physical,
- 'cpu_per_cpu_percentage': cpu_per_cpu_percentage,
- 'cpu_times': cpu_times._asdict(),
+ 'cpu_usage_percentage': cpu_usage_percentage,
+ 'cpu_number_logical': cpu_number_logical,
+ 'cpu_number_physical': cpu_number_physical,
+ 'cpu_per_cpu_percentage': cpu_per_cpu_percentage,
+ 'cpu_times': cpu_times._asdict(),
},
'memory': psutil.virtual_memory()._asdict(),
'disk': disk_usage._asdict(),
@@ -68,138 +68,138 @@ def psutil_fetching():
def psutils_html():
return '''
-
-
-
- '''
\ No newline at end of file
+
+
+
+ '''
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..a207dee
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,6 @@
+[build-system]
+requires = [
+ 'pyct',
+ 'setuptools',
+ 'wheel',
+]
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 0000000..c1fa878
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+addopts = -p no:warnings
\ No newline at end of file
diff --git a/scripts/tif_to_netcdf.py b/scripts/tif_to_netcdf.py
deleted file mode 100644
index 05b4bf2..0000000
--- a/scripts/tif_to_netcdf.py
+++ /dev/null
@@ -1,68 +0,0 @@
-import xarray as xr
-
-from mapshader.transforms import squeeze
-from mapshader.transforms import cast
-from mapshader.transforms import orient_array
-from mapshader.transforms import flip_coords
-from mapshader.transforms import reproject_raster
-
-
-def run_float(input_file, output_file, chunks=(512, 512),
- name='data', scale_factor=0.1, fill_value=-9999):
- arr = xr.open_rasterio(input_file)
- arr = squeeze(arr, 'band')
- arr = cast(arr, dtype='float64')
- arr = orient_array(arr)
- arr = flip_coords(arr, dim='y') # do we need this?
- arr = reproject_raster(arr, epsg=3857)
-
- dataset = xr.Dataset({name: (['y', 'x'], arr.chunk(chunks))},
- coords={'x': arr.coords['x'],
- 'y': arr.coords['y']})
- dataset.attrs = dict(name=name)
- dataset.to_netcdf(output_file, encoding={'data': {'dtype': 'int16',
- 'scale_factor': 0.1,
- '_FillValue': -9999}})
-
-
-def run_int(input_file, output_file, chunks=(512, 512),
- name='data', fill_value=-9999):
- arr = xr.open_rasterio(input_file)
- arr = squeeze(arr, 'band')
- arr = orient_array(arr)
- arr = flip_coords(arr, dim='y') # do we need this?
- arr = reproject_raster(arr, epsg=3857)
-
- dataset = xr.Dataset({name: (['y', 'x'], arr.chunk(chunks))},
- coords={'x': arr.coords['x'],
- 'y': arr.coords['y']})
- dataset.attrs = dict(name=name)
- dataset.to_netcdf(output_file, encoding={'data': {'dtype': 'int16',
- '_FillValue': fill_value}})
-
-
-if __name__ == '__main__':
-
- import sys
- from argparse import ArgumentParser
- from os import path
-
- parser = ArgumentParser()
- parser.add_argument('-i')
- parser.add_argument('-o')
- parser.add_argument('-f')
- parsed = parser.parse_args()
-
- input_file = path.abspath(path.expanduser(parsed.i))
- print(f'Converting {input_file} from TIFF to NetCDF File', file=sys.stdout)
-
- if not parsed.o:
- output_file = input_file.replace('.tif', '.nc')
- else:
- output_file = path.abspath(path.expanduser(parsed.o))
-
- if parsed.f:
- run_float(input_file, output_file)
- else:
- run_int(input_file, output_file)
- print(f'Conversion Complete: {output_file}', file=sys.stdout)
diff --git a/setup.py b/setup.py
index 7be3ca0..13a1c3b 100644
--- a/setup.py
+++ b/setup.py
@@ -1,33 +1,69 @@
+import os
from setuptools import setup
-setup(name='mapshader',
- use_scm_version={
- "write_to": "mapshader/_version.py",
- "write_to_template": '__version__ = "{version}"',
- "tag_regex": r"^(?Pv)?(?P[^\+]+)(?P.*)?$",
- },
- description='Simple Python GIS Web Services',
- url='https://github.com/makepath/mapshader',
- packages=['mapshader',
- 'mapshader.tests'],
- install_requires=['xarray-spatial',
- 'datashader',
- 'geopandas',
- 'click',
- 'jinja2',
- 'spatialpandas',
- 'pytest',
- 'tbb',
- 'rtree',
- 'rioxarray',
- 'matplotlib',
- 'descartes',
- 'flask',
- 'flask-cors>=3.0.10',
- 'rasterio',
- 'jupyter',
- 'pyarrow', 'psutil'],
- zip_safe=False,
- classifiers=["Programming Language :: Python :: 3",
- "License :: OSI Approved :: MIT License",
- "Operating System :: OS Independent"],
- include_package_data=True)
+import shutil
+import sys
+
+import pyct.build
+
+
+setup_args = dict(
+ name='mapshader',
+ use_scm_version={
+ 'write_to': 'mapshader/_version.py',
+ 'write_to_template': '__version__ = "{version}"',
+ 'tag_regex': r'^(?Pv)?(?P[^\+]+)(?P.*)?$',
+ },
+ description='Simple Python GIS Web Services',
+ url='https://github.com/makepath/mapshader',
+ packages=[
+ 'mapshader',
+ 'mapshader.tests',
+ ],
+ install_requires=[
+ 'xarray-spatial',
+ 'datashader',
+ 'geopandas',
+ 'click',
+ 'click_plugins',
+ 'jinja2',
+ 'spatialpandas',
+ 'pytest',
+ 'tbb',
+ 'rtree',
+ 'rioxarray',
+ 'matplotlib',
+ 'descartes',
+ 'flask',
+ 'flask-cors>=3.0.10',
+ 'rasterio',
+ 'jupyter',
+ 'pyarrow',
+ 'psutil',
+ 'pyct',
+ ],
+ zip_safe=False,
+ classifiers=[
+ 'Programming Language :: Python :: 3',
+ 'License :: OSI Approved :: MIT License',
+ 'Operating System :: OS Independent',
+ ],
+ include_package_data=True,
+ entry_points='''
+ [console_scripts]
+ mapshader=mapshader.commands:main
+
+ [mapshader.commands]
+ examples=mapshader.commands.examples:examples
+ tif_to_netcdf=mapshader.commands.tif_to_netcdf:tif_to_netcdf
+ ''',
+)
+
+if __name__ == '__main__':
+ example_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+ 'mapshader', 'examples')
+ if 'develop' not in sys.argv:
+ pyct.build.examples(example_path, __file__, force=True)
+ setup(**setup_args)
+
+ if os.path.isdir(example_path):
+ shutil.rmtree(example_path)