diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..9ff98d2c4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "cmake.configureOnEdit": false, + "cmake.configureOnOpen": false +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..6c0c9b5e7 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,151 @@ +cmake_minimum_required(VERSION 3.15) +project(python-mapnik) + +find_package(PkgConfig REQUIRED) +find_package(Python COMPONENTS Interpreter Development REQUIRED) +find_package(Boost COMPONENTS log python${Python_VERSION_MAJOR}${Python_VERSION_MINOR} REQUIRED) +find_package(mapnik CONFIG REQUIRED) +find_path(MAPBOX_GEOMETRY_INCLUDE_DIRS "mapbox/geometry.hpp" REQUIRED HINTS "${MAPNIK_INCLUDE_DIR}") + +set(PYTHON_MAPNIK_COMPILE_DEFS "") +set(PYTHON_MAPNIK_OPTIONAL_LIBS "") +set(PYTHON_MAPNIK_OPTIONAL_INC "") + +pkg_check_modules(PY_CAIRO IMPORTED_TARGET pycairo) +if(PY_CAIRO_FOUND) + list(APPEND PYTHON_MAPNIK_COMPILE_DEFS HAVE_PYCAIRO) + list(APPEND PYTHON_MAPNIK_OPTIONAL_LIBS PkgConfig::PY_CAIRO) + message(STATUS "Using pkg-config pycairo") +else() + execute_process(COMMAND ${Python_EXECUTABLE} -c "import os; import cairo; print(os.path.dirname(cairo.__file__))" OUTPUT_VARIABLE PYTHON_PY_CAIRO OUTPUT_STRIP_TRAILING_WHITESPACE) + if(${PYTHON_PY_CAIRO}) + message(STATUS "Using python pycairo from ${PYTHON_PY_CAIRO}") + file(TO_CMAKE_PATH "${PYTHON_PY_CAIRO}" PYTHON_PY_CAIRO) + list(APPEND PYTHON_MAPNIK_COMPILE_DEFS HAVE_PYCAIRO) + list(APPEND PYTHON_MAPNIK_OPTIONAL_INC "${PYTHON_PY_CAIRO}/include") + endif() +endif() + +# currently the cmake files are not installed, when installing proj via apt-get. So search via pkg-config +if(NOT PROJ_FOUND) + message(STATUS "PROJ not found via FindPROJ. Searching via pkg-config...") + pkg_check_modules(PROJ REQUIRED IMPORTED_TARGET proj) +endif() + +Python_add_library(python-mapnik MODULE + src/boost_std_shared_shim.hpp + src/mapnik_color.cpp + src/mapnik_coord.cpp + src/mapnik_datasource_cache.cpp + src/mapnik_datasource.cpp + src/mapnik_enumeration_wrapper_converter.hpp + src/mapnik_enumeration.hpp + src/mapnik_envelope.cpp + src/mapnik_expression.cpp + src/mapnik_feature.cpp + src/mapnik_featureset.cpp + src/mapnik_font_engine.cpp + src/mapnik_fontset.cpp + src/mapnik_gamma_method.cpp + src/mapnik_geometry.cpp + src/mapnik_grid_view.cpp + src/mapnik_grid.cpp + src/mapnik_image_view.cpp + src/mapnik_image.cpp + src/mapnik_label_collision_detector.cpp + src/mapnik_layer.cpp + src/mapnik_logger.cpp + src/mapnik_map.cpp + src/mapnik_palette.cpp + src/mapnik_parameters.cpp + src/mapnik_proj_transform.cpp + src/mapnik_projection.cpp + src/mapnik_python.cpp + src/mapnik_query.cpp + src/mapnik_raster_colorizer.cpp + src/mapnik_rule.cpp + src/mapnik_scaling_method.cpp + src/mapnik_style.cpp + src/mapnik_svg.hpp + src/mapnik_symbolizer.cpp + src/mapnik_threads.hpp + src/mapnik_value_converter.hpp + src/mapnik_view_transform.cpp + src/python_grid_utils.cpp + src/python_grid_utils.hpp + src/python_optional.hpp + src/python_to_value.hpp +) + + +target_link_libraries(python-mapnik PRIVATE + Boost::boost + Boost::log + Boost::python${Python_VERSION_MAJOR}${Python_VERSION_MINOR} + mapnik::core + mapnik::json + mapnik::wkt + mapnik::mapnik + ${PYTHON_MAPNIK_OPTIONAL_LIBS} +) +target_include_directories(python-mapnik PRIVATE + ${MAPBOX_GEOMETRY_INCLUDE_DIRS} + ${PYTHON_MAPNIK_OPTIONAL_INC} +) + +set_target_properties(python-mapnik PROPERTIES + OUTPUT_NAME "_mapnik" + PREFIX "" +) + + + +target_compile_definitions(python-mapnik PRIVATE ${PYTHON_MAPNIK_COMPILE_DEFS}) + + +# copy plugins, fonts +file(TO_CMAKE_PATH "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" MODULE_PATH) +set(MODULE_LIB_DIR "${MODULE_PATH}/lib/mapnik") +set(MODULE_FONTS_DIR "${MODULE_LIB_DIR}/fonts") +set(MODULE_PLUGINS_DIR "${MODULE_LIB_DIR}/input") +file(COPY "${MAPNIK_FONTS_DIR}/" DESTINATION "${MODULE_FONTS_DIR}/") + +mapnik_find_plugin_dir(MAPNIK_PLUGINS_DIR) +file(COPY "${MAPNIK_PLUGINS_DIR}/" DESTINATION "${MODULE_PLUGINS_DIR}/" PATTERN "*.input") + +# copy dlls on windows +if(WIN32) + file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$_install_deps.cmake CONTENT " + file(GET_RUNTIME_DEPENDENCIES + RESOLVED_DEPENDENCIES_VAR RESOLVED_DEPS + UNRESOLVED_DEPENDENCIES_VAR UNRESOLVED_DEPS + LIBRARIES + \"${MODULE_PLUGINS_DIR}/csv.input\" + \"${MODULE_PLUGINS_DIR}/gdal.input\" + \"${MODULE_PLUGINS_DIR}/geobuf.input\" + \"${MODULE_PLUGINS_DIR}/geojson.input\" + \"${MODULE_PLUGINS_DIR}/ogr.input\" + \"${MODULE_PLUGINS_DIR}/pgraster.input\" + \"${MODULE_PLUGINS_DIR}/postgis.input\" + \"${MODULE_PLUGINS_DIR}/raster.input\" + \"${MODULE_PLUGINS_DIR}/shape.input\" + \"${MODULE_PLUGINS_DIR}/sqlite.input\" + \"${MODULE_PLUGINS_DIR}/topojson.input\" + ${MODULE_FILE_PATH} + DIRECTORIES \"${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/\" + PRE_EXCLUDE_REGEXES \"api-ms-*\" \"ext-ms-*\" + POST_EXCLUDE_REGEXES \".*system32/.*\\\\.dll\" + ) + message(STATUS \"X \${RESOLVED_DEPS}\") + #foreach(dep \${RESOLVED_DEPS}) + # file(COPY \${dep} DESTINATION \"${MODULE_PATH}\") + #endforeach() + foreach(dep \${UNRESOLVED_DEPS}) + message(WARNING \"Runtime dependency \${dep} could not be resolved.\") + endforeach() + ") + add_custom_command(TARGET python-mapnik POST_BUILD COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/$_install_deps.cmake) +endif() + +# write configure file +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/paths.py.in" "${MODULE_PATH}/paths.py") diff --git a/build.py b/build.py deleted file mode 100644 index 0f94826b6..000000000 --- a/build.py +++ /dev/null @@ -1,120 +0,0 @@ -import glob -import os -from subprocess import Popen, PIPE -from distutils import sysconfig - -Import('env') - -def call(cmd, silent=True): - stdin, stderr = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate() - if not stderr: - return stdin.strip() - elif not silent: - print stderr - - -prefix = env['PREFIX'] -target_path = os.path.normpath(sysconfig.get_python_lib() + os.path.sep + env['MAPNIK_NAME']) - -py_env = env.Clone() - -py_env.Append(CPPPATH = sysconfig.get_python_inc()) - -py_env.Append(CPPDEFINES = env['LIBMAPNIK_DEFINES']) - -py_env['LIBS'] = [env['MAPNIK_NAME'],'libboost_python'] - -link_all_libs = env['LINKING'] == 'static' or env['RUNTIME_LINK'] == 'static' - -# even though boost_thread is no longer used in mapnik core -# we need to link in for boost_python to avoid missing symbol: _ZN5boost6detail12get_tss_dataEPKv / boost::detail::get_tss_data -py_env.AppendUnique(LIBS = 'boost_thread%s' % env['BOOST_APPEND']) - -if link_all_libs: - py_env.AppendUnique(LIBS=env['LIBMAPNIK_LIBS']) - -# note: on linux -lrt must be linked after thread to avoid: undefined symbol: clock_gettime -if env['RUNTIME_LINK'] == 'static' and env['PLATFORM'] == 'Linux': - py_env.AppendUnique(LIBS='rt') - -# TODO - do solaris/fedora need direct linking too? -python_link_flag = '' -if env['PLATFORM'] == 'Darwin': - python_link_flag = '-undefined dynamic_lookup' - -paths = ''' -"""Configuration paths of Mapnik fonts and input plugins (auto-generated by SCons).""" - -from os.path import normpath,join,dirname - -mapniklibpath = '%s' -mapniklibpath = normpath(join(dirname(__file__),mapniklibpath)) -''' - -paths += "inputpluginspath = join(mapniklibpath,'input')\n" - -if env['SYSTEM_FONTS']: - paths += "fontscollectionpath = normpath('%s')\n" % env['SYSTEM_FONTS'] -else: - paths += "fontscollectionpath = join(mapniklibpath,'fonts')\n" - -paths += "__all__ = [mapniklibpath,inputpluginspath,fontscollectionpath]\n" - -if not os.path.exists(env['MAPNIK_NAME']): - os.mkdir(env['MAPNIK_NAME']) - -file('mapnik/paths.py','w').write(paths % (env['MAPNIK_LIB_DIR'])) - -# force open perms temporarily so that `sudo scons install` -# does not later break simple non-install non-sudo rebuild -try: - os.chmod('mapnik/paths.py',0666) -except: pass - -# install the shared object beside the module directory -sources = glob.glob('src/*.cpp') - -if 'install' in COMMAND_LINE_TARGETS: - # install the core mapnik python files, including '__init__.py' - init_files = glob.glob('mapnik/*.py') - if 'mapnik/paths.py' in init_files: - init_files.remove('mapnik/paths.py') - init_module = env.Install(target_path, init_files) - env.Alias(target='install', source=init_module) - # fix perms and install the custom generated 'paths.py' - targetp = os.path.join(target_path,'paths.py') - env.Alias("install", targetp) - # use env.Command rather than env.Install - # to enable setting proper perms on `paths.py` - env.Command( targetp, 'mapnik/paths.py', - [ - Copy("$TARGET","$SOURCE"), - Chmod("$TARGET", 0644), - ]) - -if 'uninstall' not in COMMAND_LINE_TARGETS: - if env['HAS_CAIRO']: - py_env.Append(CPPPATH = env['CAIRO_CPPPATHS']) - py_env.Append(CPPDEFINES = '-DHAVE_CAIRO') - if link_all_libs: - py_env.Append(LIBS=env['CAIRO_ALL_LIBS']) - - if env['HAS_PYCAIRO']: - py_env.Append(CPPDEFINES = '-DHAVE_PYCAIRO') - py_env.Append(CPPPATH = env['PYCAIRO_PATHS']) - -py_env.Append(LINKFLAGS=python_link_flag) -py_env.AppendUnique(LIBS='mapnik-json') -py_env.AppendUnique(LIBS='mapnik-wkt') - -_mapnik = py_env.LoadableModule('mapnik/_mapnik', sources, LDMODULEPREFIX='', LDMODULESUFFIX='.so') - -Depends(_mapnik, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME'])) -Depends(_mapnik, env.subst('../../src/json/libmapnik-json${LIBSUFFIX}')) -Depends(_mapnik, env.subst('../../src/wkt/libmapnik-wkt${LIBSUFFIX}')) - -if 'uninstall' not in COMMAND_LINE_TARGETS: - pymapniklib = env.Install(target_path,_mapnik) - py_env.Alias(target='install',source=pymapniklib) - -env['create_uninstall_target'](env, target_path) diff --git a/mapnik/__init__.py b/mapnik/__init__.py index 4d99ad14b..213242632 100644 --- a/mapnik/__init__.py +++ b/mapnik/__init__.py @@ -156,7 +156,7 @@ def forward(self, projection): Example: Project the geographic coordinates of the city center of Stuttgart into the local map projection (GK Zone 3/DHDN, EPSG 31467) - >>> p = Projection('+init=epsg:31467') + >>> p = Projection('epsg:31467') >>> Coord(9.1, 48.7).forward(p) Coord(3507360.12813,5395719.2749) """ @@ -176,7 +176,7 @@ def inverse(self, projection): city center of Stuttgart in the local map projection (GK Zone 3/DHDN, EPSG 31467) into geographic coordinates: - >>> p = Projection('+init=epsg:31467') + >>> p = Projection('epsg:31467') >>> Coord(3507360.12813,5395719.2749).inverse(p) Coord(9.1, 48.7) """ diff --git a/setup.py b/setup.py index 9985da5a2..36c411de8 100755 --- a/setup.py +++ b/setup.py @@ -1,258 +1,122 @@ -#! /usr/bin/env python - + +# -*- coding: utf-8 -*- import os -import os.path import re -import shutil import subprocess import sys -import glob -from distutils import sysconfig -from ctypes.util import find_library - -from setuptools import Command, Extension, setup - -PYTHON3 = sys.version_info.major == 3 - - -# Utils -def check_output(args): - output = subprocess.check_output(args) - if PYTHON3: - # check_output returns bytes in PYTHON3. - output = output.decode() - return output.rstrip('\n') +from setuptools import setup, Extension +from setuptools.command.build_ext import build_ext + +# Convert distutils Windows platform specifiers to CMake -A arguments +PLAT_TO_CMAKE = { + "win32": "Win32", + "win-amd64": "x64", + "win-arm32": "ARM", + "win-arm64": "ARM64", +} + + +# A CMakeExtension needs a sourcedir instead of a file list. +# The name must be the _single_ output extension from the CMake build. +# If you need multiple extensions, see scikit-build. +class CMakeExtension(Extension): + def __init__(self, name, sourcedir=""): + Extension.__init__(self, name, sources=[]) + self.sourcedir = os.path.abspath(sourcedir) + + +class CMakeBuild(build_ext): + def build_extension(self, ext): + extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) + if not extdir.endswith(os.path.sep): + extdir += os.path.sep + extdir+= "mapnik" + # required for auto-detection of auxiliary "native" libs + if not extdir.endswith(os.path.sep): + extdir += os.path.sep + + cfg = "Debug" if self.debug else "Release" + + # CMake lets you override the generator - we need to check this. + # Can be set with Conda-Build, for example. + cmake_generator = os.environ.get("CMAKE_GENERATOR", "") + + vcpkg_toolchain_file = os.environ.get("VCPKG_TOOLCHAIN_FILE", "vcpkg/scripts/buildsystems/vcpkg.cmake") + + # Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON + # EXAMPLE_VERSION_INFO shows you how to pass a value into the C++ code + # from Python. + cmake_args = [ + "-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={}".format(extdir), + "-DCMAKE_BUILD_TYPE={}".format(cfg), # not used on MSVC, but no harm + "-DCMAKE_TOOLCHAIN_FILE={}".format(vcpkg_toolchain_file) + ] + build_args = [] + + if self.compiler.compiler_type != "msvc": + # Using Ninja-build since it a) is available as a wheel and b) + # multithreads automatically. MSVC would require all variables be + # exported for Ninja to pick it up, which is a little tricky to do. + # Users can override the generator with CMAKE_GENERATOR in CMake + # 3.15+. + if not cmake_generator: + try: + import ninja # noqa: F401 + + cmake_args += ["-GNinja"] + except ImportError: + pass -def clean_boost_name(name): - name = name.split('.')[0] - if name.startswith('lib'): - name = name[3:] - return name - - -def find_boost_library(_id): - suffixes = [ - "", # standard naming - "-mt" # former naming schema for multithreading build - ] - if "python" in _id: - # Debian naming convention for versions installed in parallel - suffixes.insert(0, "-py%d%d" % (sys.version_info.major, - sys.version_info.minor)) - suffixes.insert(1, "%d%d" % (sys.version_info.major, - sys.version_info.minor)) - # standard suffix for Python3 - suffixes.insert(2, sys.version_info.major) - for suf in suffixes: - name = "%s%s" % (_id, suf) - lib = find_library(name) - if lib is not None: - return name - - -def get_boost_library_names(): - wanted = ['boost_python', 'boost_thread', 'boost_system'] - found = [] - missing = [] - for _id in wanted: - name = os.environ.get("%s_LIB" % _id.upper(), find_boost_library(_id)) - if name: - found.append(name) else: - missing.append(_id) - if missing: - msg = "" - for name in missing: - msg += ("\nMissing {} boost library, try to add its name with " - "{}_LIB environment var.").format(name, name.upper()) - raise EnvironmentError(msg) - return found - - -class WhichBoostCommand(Command): - description = 'Output found boost names. Useful for debug.' - user_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - print("\n".join(get_boost_library_names())) - - -cflags = sysconfig.get_config_var('CFLAGS') -sysconfig._config_vars['CFLAGS'] = re.sub( - ' +', ' ', cflags.replace('-g ', '').replace('-Os', '').replace('-arch i386', '')) -opt = sysconfig.get_config_var('OPT') -sysconfig._config_vars['OPT'] = re.sub( - ' +', ' ', opt.replace('-g ', '').replace('-Os', '')) -ldshared = sysconfig.get_config_var('LDSHARED') -sysconfig._config_vars['LDSHARED'] = re.sub( - ' +', ' ', ldshared.replace('-g ', '').replace('-Os', '').replace('-arch i386', '')) -ldflags = sysconfig.get_config_var('LDFLAGS') -sysconfig._config_vars['LDFLAGS'] = re.sub( - ' +', ' ', ldflags.replace('-g ', '').replace('-Os', '').replace('-arch i386', '')) -pycflags = sysconfig.get_config_var('PY_CFLAGS') -sysconfig._config_vars['PY_CFLAGS'] = re.sub( - ' +', ' ', pycflags.replace('-g ', '').replace('-Os', '').replace('-arch i386', '')) -sysconfig._config_vars['CFLAGSFORSHARED'] = '' -os.environ['ARCHFLAGS'] = '' - -if os.environ.get("MASON_BUILD", "false") == "true": - # run bootstrap.sh to get mason builds - subprocess.call(['./bootstrap.sh']) - mapnik_config = 'mason_packages/.link/bin/mapnik-config' - mason_build = True -else: - mapnik_config = 'mapnik-config' - mason_build = False - - -linkflags = [] -lib_path = os.path.join(check_output([mapnik_config, '--prefix']),'lib') -linkflags.extend(check_output([mapnik_config, '--libs']).split(' ')) -linkflags.extend(check_output([mapnik_config, '--ldflags']).split(' ')) -linkflags.extend(check_output([mapnik_config, '--dep-libs']).split(' ')) -linkflags.extend([ -'-lmapnik-wkt', -'-lmapnik-json', -] + ['-l%s' % i for i in get_boost_library_names()]) -# Dynamically make the mapnik/paths.py file -f_paths = open('mapnik/paths.py', 'w') -f_paths.write('import os\n') -f_paths.write('\n') - -input_plugin_path = check_output([mapnik_config, '--input-plugins']) -font_path = check_output([mapnik_config, '--fonts']) - -if mason_build: - try: - if sys.platform == 'darwin': - base_f = 'libmapnik.dylib' - else: - base_f = 'libmapnik.so' - f = os.path.join(lib_path, base_f) - if not os.path.exists(os.path.join('mapnik', 'lib')): - os.makedirs(os.path.join('mapnik', 'lib')) - shutil.copyfile(f, os.path.join('mapnik', 'lib', base_f)) - except shutil.Error: - pass - input_plugin_files = os.listdir(input_plugin_path) - input_plugin_files = [os.path.join( - input_plugin_path, f) for f in input_plugin_files] - if not os.path.exists(os.path.join('mapnik', 'lib', 'mapnik', 'input')): - os.makedirs(os.path.join('mapnik', 'lib', 'mapnik', 'input')) - for f in input_plugin_files: - try: - shutil.copyfile(f, os.path.join( - 'mapnik', 'lib', 'mapnik', 'input', os.path.basename(f))) - except shutil.Error: - pass - font_files = os.listdir(font_path) - font_files = [os.path.join(font_path, f) for f in font_files] - if not os.path.exists(os.path.join('mapnik', 'lib', 'mapnik', 'fonts')): - os.makedirs(os.path.join('mapnik', 'lib', 'mapnik', 'fonts')) - for f in font_files: - try: - shutil.copyfile(f, os.path.join( - 'mapnik', 'lib', 'mapnik', 'fonts', os.path.basename(f))) - except shutil.Error: - pass - f_paths.write( - 'mapniklibpath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "lib")\n') - f_paths.write("inputpluginspath = os.path.join(mapniklibpath, 'mapnik', 'input')\n") - f_paths.write("fontscollectionpath = os.path.join(mapniklibpath, 'mapnik', 'fonts')\n") - f_paths.write( - "__all__ = [mapniklibpath,inputpluginspath,fontscollectionpath]\n") - f_paths.close() -else: - if os.environ.get('LIB_DIR_NAME'): - mapnik_lib_path = lib_path + os.environ.get('LIB_DIR_NAME') - else: - mapnik_lib_path = lib_path + "/mapnik" - f_paths.write("mapniklibpath = '{path}'\n".format(path=mapnik_lib_path)) - f_paths.write('mapniklibpath = os.path.normpath(mapniklibpath)\n') - f_paths.write( - "inputpluginspath = '{path}'\n".format(path=input_plugin_path)) - f_paths.write( - "fontscollectionpath = '{path}'\n".format(path=font_path)) - f_paths.write( - "__all__ = [mapniklibpath,inputpluginspath,fontscollectionpath]\n") - f_paths.close() - - -if mason_build: - - share_dir = 'share' - - for dep in ['icu','gdal','proj']: - share_path = os.path.join('mapnik', share_dir, dep) - if not os.path.exists(share_path): - os.makedirs(share_path) - - icu_path = 'mason_packages/.link/share/icu/*/*.dat' - icu_files = glob.glob(icu_path) - if len(icu_files) != 1: - raise Exception("Failed to find icu dat file at "+ icu_path) - for f in icu_files: - shutil.copyfile(f, os.path.join( - 'mapnik', share_dir, 'icu', os.path.basename(f))) - - gdal_path = 'mason_packages/.link/share/gdal/' - gdal_files = os.listdir(gdal_path) - gdal_files = [os.path.join(gdal_path, f) for f in gdal_files] - for f in gdal_files: - try: - shutil.copyfile(f, os.path.join( - 'mapnik', share_dir, 'gdal', os.path.basename(f))) - except shutil.Error: - pass - - proj_path = 'mason_packages/.link/share/proj/' - proj_files = os.listdir(proj_path) - proj_files = [os.path.join(proj_path, f) for f in proj_files] - for f in proj_files: - try: - shutil.copyfile(f, os.path.join( - 'mapnik', share_dir, 'proj', os.path.basename(f))) - except shutil.Error: - pass - -extra_comp_args = check_output([mapnik_config, '--cflags']).split(' ') - -extra_comp_args = list(filter(lambda arg: arg != "-fvisibility=hidden", extra_comp_args)) - -if os.environ.get("PYCAIRO", "false") == "true": - try: - extra_comp_args.append('-DHAVE_PYCAIRO') - print("-I%s/include/pycairo".format(sys.exec_prefix)) - extra_comp_args.append("-I{0}/include/pycairo".format(sys.exec_prefix)) - #extra_comp_args.extend(check_output(["pkg-config", '--cflags', 'pycairo']).strip().split(' ')) - #linkflags.extend(check_output(["pkg-config", '--libs', 'pycairo']).strip().split(' ')) - except: - raise Exception("Failed to find compiler options for pycairo") - -if sys.platform == 'darwin': - extra_comp_args.append('-mmacosx-version-min=10.11') - # silence warning coming from boost python macros which - # would is hard to silence via pragma - extra_comp_args.append('-Wno-parentheses-equality') - linkflags.append('-mmacosx-version-min=10.11') -else: - linkflags.append('-lrt') - linkflags.append('-Wl,-z,origin') - linkflags.append('-Wl,-rpath=$ORIGIN/lib') + # Single config generators are handled "normally" + single_config = any(x in cmake_generator for x in {"NMake", "Ninja"}) + + # CMake allows an arch-in-generator style for backward compatibility + contains_arch = any(x in cmake_generator for x in {"ARM", "Win64"}) + + # Specify the arch if using MSVC generator, but only if it doesn't + # contain a backward-compatibility arch spec already in the + # generator name. + if not single_config and not contains_arch: + cmake_args += ["-A", PLAT_TO_CMAKE[self.plat_name]] + + # Multi-config generators have a different way to specify configs + if not single_config: + cmake_args += [ + "-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}".format(cfg.upper(), extdir) + ] + build_args += ["--config", cfg] + + if sys.platform.startswith("darwin"): + # Cross-compile support for macOS - respect ARCHFLAGS if set + archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", "")) + if archs: + cmake_args += ["-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs))] + + # Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level + # across all generators. + if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ: + # self.parallel is a Python 3 only way to set parallel jobs by hand + # using -j in the build_ext call, not supported by pip or PyPA-build. + if hasattr(self, "parallel") and self.parallel: + # CMake 3.12+ only. + build_args += ["-j{}".format(self.parallel)] + + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + + subprocess.check_call( + ["cmake", ext.sourcedir] + cmake_args, cwd=self.build_temp + ) + subprocess.check_call( + ["cmake", "--build", "."] + build_args, cwd=self.build_temp + ) -if os.environ.get("CC", False) == False: - os.environ["CC"] = check_output([mapnik_config, '--cxx']) -if os.environ.get("CXX", False) == False: - os.environ["CXX"] = check_output([mapnik_config, '--cxx']) +# The information here can also be placed in setup.cfg - better separation of +# logic and declaration, and simpler if you include description/version in a file. setup( name="mapnik", version="4.0.0", @@ -270,48 +134,7 @@ def run(self): 'mapnik': ['lib/*.*', 'lib/*/*/*', 'share/*/*'], }, test_suite='nose.collector', - cmdclass={ - 'whichboost': WhichBoostCommand, - }, - ext_modules=[ - Extension('mapnik._mapnik', [ - 'src/mapnik_color.cpp', - 'src/mapnik_coord.cpp', - 'src/mapnik_datasource.cpp', - 'src/mapnik_datasource_cache.cpp', - 'src/mapnik_envelope.cpp', - 'src/mapnik_expression.cpp', - 'src/mapnik_feature.cpp', - 'src/mapnik_featureset.cpp', - 'src/mapnik_font_engine.cpp', - 'src/mapnik_fontset.cpp', - 'src/mapnik_gamma_method.cpp', - 'src/mapnik_geometry.cpp', - 'src/mapnik_grid.cpp', - 'src/mapnik_grid_view.cpp', - 'src/mapnik_image.cpp', - 'src/mapnik_image_view.cpp', - 'src/mapnik_label_collision_detector.cpp', - 'src/mapnik_layer.cpp', - 'src/mapnik_logger.cpp', - 'src/mapnik_map.cpp', - 'src/mapnik_palette.cpp', - 'src/mapnik_parameters.cpp', - 'src/mapnik_proj_transform.cpp', - 'src/mapnik_projection.cpp', - 'src/mapnik_python.cpp', - 'src/mapnik_query.cpp', - 'src/mapnik_raster_colorizer.cpp', - 'src/mapnik_rule.cpp', - 'src/mapnik_scaling_method.cpp', - 'src/mapnik_style.cpp', - 'src/mapnik_symbolizer.cpp', - 'src/mapnik_view_transform.cpp', - 'src/python_grid_utils.cpp', - ], - language='c++', - extra_compile_args=extra_comp_args, - extra_link_args=linkflags, - ) - ] + ext_modules=[CMakeExtension("python-mapnik")], + cmdclass={"build_ext": CMakeBuild}, + zip_safe=False ) diff --git a/src/mapnik_layer.cpp b/src/mapnik_layer.cpp index a7caf38d3..4fc7ea579 100644 --- a/src/mapnik_layer.cpp +++ b/src/mapnik_layer.cpp @@ -146,13 +146,13 @@ void export_layer() class_("Layer", "A Mapnik map layer.", init >( "Create a Layer with a named string and, optionally, an srs string.\n" "\n" - "The srs can be either a Proj.4 epsg code ('+init=epsg:') or\n" - "of a Proj.4 literal ('+proj=').\n" - "If no srs is specified it will default to '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n" + "The srs can be either a Proj epsg code ('epsg:') or\n" + "of a Proj literal ('+proj=').\n" + "If no srs is specified it will default to 'epsg:4326'\n" "\n" "Usage:\n" ">>> from mapnik import Layer\n" - ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" + ">>> lyr = Layer('My Layer','epsg:4326')\n" ">>> lyr\n" "\n" )) @@ -166,7 +166,7 @@ void export_layer() "\n" "Usage:\n" ">>> from mapnik import Layer\n" - ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" + ">>> lyr = Layer('My Layer','epsg:4326')\n" ">>> lyr.envelope()\n" "box2d(-1.0,-1.0,0.0,0.0) # default until a datasource is loaded\n" ) @@ -183,7 +183,7 @@ void export_layer() "\n" "Usage:\n" ">>> from mapnik import Layer\n" - ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" + ">>> lyr = Layer('My Layer','epsg:4326')\n" ">>> lyr.visible(1.0/1000000)\n" "True\n" ">>> lyr.active = False\n" @@ -198,7 +198,7 @@ void export_layer() "\n" "Usage:\n" ">>> from mapnik import Layer\n" - ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" + ">>> lyr = Layer('My Layer','epsg:4326')\n" ">>> lyr.active\n" "True # Active by default\n" ">>> lyr.active = False # set False to disable layer rendering\n" @@ -213,7 +213,7 @@ void export_layer() "\n" "Usage:\n" ">>> from mapnik import Layer\n" - ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" + ">>> lyr = Layer('My Layer','epsg:4326')\n" ">>> lyr.status\n" "True # Active by default\n" ">>> lyr.status = False # set False to disable layer rendering\n" @@ -250,7 +250,7 @@ void export_layer() "\n" "Usage:\n" ">>> from mapnik import Layer, Datasource\n" - ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" + ">>> lyr = Layer('My Layer','epsg:4326')\n" ">>> lyr.datasource = Datasource(type='shape',file='world_borders')\n" ">>> lyr.datasource\n" "\n" @@ -285,7 +285,7 @@ void export_layer() "\n" "Usage:\n" ">>> from mapnik import Layer\n" - ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" + ">>> lyr = Layer('My Layer','epsg:4326')\n" ">>> lyr.maximum_scale_denominator\n" "1.7976931348623157e+308 # default is the numerical maximum\n" ">>> lyr.maximum_scale_denominator = 1.0/1000000\n" @@ -300,7 +300,7 @@ void export_layer() "\n" "Usage:\n" ">>> from mapnik import Layer\n" - ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" + ">>> lyr = Layer('My Layer','epsg:4326')\n" ">>> lyr.minimum_scale_denominator # default is 0\n" "0.0\n" ">>> lyr.minimum_scale_denominator = 1.0/1000000\n" @@ -315,7 +315,7 @@ void export_layer() "\n" "Usage:\n" ">>> from mapnik import Layer\n" - ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" + ">>> lyr = Layer('My Layer','epsg:4326')\n" ">>> lyr.name\n" "'My Layer'\n" ">>> lyr.name = 'New Name'\n" @@ -330,7 +330,7 @@ void export_layer() "\n" "Usage:\n" ">>> from mapnik import layer\n" - ">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" + ">>> lyr = layer('My layer','epsg:4326')\n" ">>> lyr.queryable\n" "False # Not queryable by default\n" ">>> lyr.queryable = True\n" @@ -345,12 +345,12 @@ void export_layer() "\n" "Usage:\n" ">>> from mapnik import layer\n" - ">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" + ">>> lyr = layer('My layer','epsg:4326')\n" ">>> lyr.srs\n" - "'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' # The default srs if not initialized with custom srs\n" - ">>> # set to google mercator with Proj.4 literal\n" + "'epsg:4326' # The default srs if not initialized with custom srs\n" + ">>> # set to google mercator with Proj literal\n" "... \n" - ">>> lyr.srs = '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over'\n" + ">>> lyr.srs = 'epsg:3857'\n" ) .add_property("group_by", @@ -367,7 +367,7 @@ void export_layer() "\n" "Usage:\n" ">>> from mapnik import layer\n" - ">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n" + ">>> lyr = layer('My layer','epsg:4326')\n" ">>> lyr.styles\n" "\n" ">>> len(lyr.styles)\n" diff --git a/src/mapnik_map.cpp b/src/mapnik_map.cpp index 3036cf89b..3587e5d8a 100644 --- a/src/mapnik_map.cpp +++ b/src/mapnik_map.cpp @@ -165,9 +165,9 @@ void export_map() class_("Map","The map object.",init >( ( arg("width"),arg("height"),arg("srs") ), "Create a Map with a width and height as integers and, optionally,\n" - "an srs string either with a Proj.4 epsg code ('+init=epsg:')\n" - "or with a Proj.4 literal ('+proj=').\n" - "If no srs is specified the map will default to '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n" + "an srs string either with a Proj epsg code ('epsg:')\n" + "or with a Proj literal ('+proj=').\n" + "If no srs is specified the map will default to 'epsg:4326'\n" "\n" "Usage:\n" ">>> from mapnik import Map\n" @@ -175,7 +175,7 @@ void export_map() ">>> m\n" "\n" ">>> m.srs\n" - "'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n" + "'epsg:4326'\n" )) .def("append_style",insert_style, @@ -502,22 +502,22 @@ void export_map() .add_property("srs", make_function(&Map::srs,return_value_policy()), &Map::set_srs, - "Spatial reference in Proj.4 format.\n" + "Spatial reference in Proj format.\n" "Either an epsg code or proj literal.\n" "For example, a proj literal:\n" - "\t'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n" + "\t'epsg:4326'\n" "and a proj epsg code:\n" - "\t'+init=epsg:4326'\n" + "\t'epsg:4326'\n" "\n" "Note: using epsg codes requires the installation of\n" - "the Proj.4 'epsg' data file normally found in '/usr/local/share/proj'\n" + "the Proj 'epsg' data file normally found in '/usr/local/share/proj'\n" "\n" "Usage:\n" ">>> m.srs\n" - "'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' # The default srs if not initialized with custom srs\n" + "'epsg:4326' # The default srs if not initialized with custom srs\n" ">>> # set to google mercator with Proj.4 literal\n" "... \n" - ">>> m.srs = '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over'\n" + ">>> m.srs = 'epsg:3857'\n" ) .add_property("width", diff --git a/src/mapnik_proj_transform.cpp b/src/mapnik_proj_transform.cpp index fc753564c..bbb37866c 100644 --- a/src/mapnik_proj_transform.cpp +++ b/src/mapnik_proj_transform.cpp @@ -23,11 +23,9 @@ #include #include "boost_std_shared_shim.hpp" -#pragma GCC diagnostic push #include #include #include -#pragma GCC diagnostic pop // mapnik #include @@ -48,7 +46,7 @@ struct proj_transform_pickle_suite : boost::python::pickle_suite getinitargs(const proj_transform& p) { using namespace boost::python; - return boost::python::make_tuple(p.source(),p.dest()); + return boost::python::make_tuple(p.definition()); } }; @@ -61,8 +59,7 @@ mapnik::coord2d forward_transform_c(mapnik::proj_transform& t, mapnik::coord2d c double z = 0.0; if (!t.forward(x,y,z)) { std::ostringstream s; - s << "Failed to forward project " - << "from " << t.source().params() << " to: " << t.dest().params(); + s << "Failed to forward project " << t.definition(); throw std::runtime_error(s.str()); } return mapnik::coord2d(x,y); @@ -75,8 +72,7 @@ mapnik::coord2d backward_transform_c(mapnik::proj_transform& t, mapnik::coord2d double z = 0.0; if (!t.backward(x,y,z)) { std::ostringstream s; - s << "Failed to back project " - << "from " << t.dest().params() << " to: " << t.source().params(); + s << "Failed to back project " << t.definition(); throw std::runtime_error(s.str()); } return mapnik::coord2d(x,y); @@ -87,8 +83,7 @@ mapnik::box2d forward_transform_env(mapnik::proj_transform& t, mapnik::b mapnik::box2d new_box = box; if (!t.forward(new_box)) { std::ostringstream s; - s << "Failed to forward project " - << "from " << t.source().params() << " to: " << t.dest().params(); + s << "Failed to forward project " << t.definition(); throw std::runtime_error(s.str()); } return new_box; @@ -99,8 +94,7 @@ mapnik::box2d backward_transform_env(mapnik::proj_transform& t, mapnik:: mapnik::box2d new_box = box; if (!t.backward(new_box)){ std::ostringstream s; - s << "Failed to back project " - << "from " << t.dest().params() << " to: " << t.source().params(); + s << "Failed to back project " << t.definition(); throw std::runtime_error(s.str()); } return new_box; @@ -111,8 +105,7 @@ mapnik::box2d forward_transform_env_p(mapnik::proj_transform& t, mapnik: mapnik::box2d new_box = box; if (!t.forward(new_box,points)) { std::ostringstream s; - s << "Failed to forward project " - << "from " << t.source().params() << " to: " << t.dest().params(); + s << "Failed to forward project " << t.definition(); throw std::runtime_error(s.str()); } return new_box; @@ -123,8 +116,7 @@ mapnik::box2d backward_transform_env_p(mapnik::proj_transform& t, mapnik mapnik::box2d new_box = box; if (!t.backward(new_box,points)){ std::ostringstream s; - s << "Failed to back project " - << "from " << t.dest().params() << " to: " << t.source().params(); + s << "Failed to back project " << t.definition(); throw std::runtime_error(s.str()); } return new_box; @@ -136,7 +128,7 @@ void export_proj_transform () { using namespace boost::python; - class_("ProjTransform", init< projection const&, projection const& >()) + class_("ProjTransform", init()) .def_pickle(proj_transform_pickle_suite()) .def("forward", forward_transform_c) .def("backward",backward_transform_c) @@ -144,6 +136,7 @@ void export_proj_transform () .def("backward",backward_transform_env) .def("forward", forward_transform_env_p) .def("backward",backward_transform_env_p) + .def("definition",&proj_transform::definition) ; } diff --git a/src/mapnik_projection.cpp b/src/mapnik_projection.cpp index c2088cd89..8875fa62b 100644 --- a/src/mapnik_projection.cpp +++ b/src/mapnik_projection.cpp @@ -95,8 +95,8 @@ void export_projection () using namespace boost::python; class_("Projection", "Represents a map projection.",init( - (arg("proj4_string")), - "Constructs a new projection from its PROJ.4 string representation.\n" + (arg("proj_string")), + "Constructs a new projection from its PROJ string representation.\n" "\n" "The constructor will throw a RuntimeError in case the projection\n" "cannot be initialized.\n" @@ -105,9 +105,9 @@ void export_projection () .def_pickle(projection_pickle_suite()) .def ("params", make_function(&projection::params, return_value_policy()), - "Returns the PROJ.4 string for this projection.\n") + "Returns the PROJ string for this projection.\n") .def ("expanded",&projection::expanded, - "normalize PROJ.4 definition by expanding +init= syntax\n") + "normalize PROJ definition by expanding epsg:XXXX syntax\n") .add_property ("geographic", &projection::is_geographic, "This property is True if the projection is a geographic projection\n" "(i.e. it uses lon/lat coordinates)\n") diff --git a/src/mapnik_python.cpp b/src/mapnik_python.cpp index 14523b034..50b5544e4 100644 --- a/src/mapnik_python.cpp +++ b/src/mapnik_python.cpp @@ -598,9 +598,9 @@ std::string mapnik_version_string() return MAPNIK_VERSION_STRING; } -bool has_proj4() +bool has_proj() { -#if defined(MAPNIK_USE_PROJ4) +#if defined(MAPNIK_USE_PROJ) return true; #else return false; @@ -1035,8 +1035,8 @@ BOOST_PYTHON_MODULE(_mapnik) ">>> m = Map(256,256)\n" ">>> load_map(m,'mapfile_wgs84.xml')\n" ">>> m.srs\n" - "'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n" - ">>> m.srs = '+init=espg:3395'\n" + "'epsg:4326'\n" + ">>> m.srs = 'espg:3395'\n" ">>> save_map(m,'mapfile_mercator.xml')\n" "\n" ); @@ -1045,7 +1045,7 @@ BOOST_PYTHON_MODULE(_mapnik) def("save_map_to_string", &save_map_to_string, save_map_to_string_overloads()); def("mapnik_version", &mapnik_version,"Get the Mapnik version number"); def("mapnik_version_string", &mapnik_version_string,"Get the Mapnik version string"); - def("has_proj4", &has_proj4, "Get proj4 status"); + def("has_proj", &has_proj, "Get proj status"); def("has_jpeg", &has_jpeg, "Get jpeg read/write support status"); def("has_png", &has_png, "Get png read/write support status"); def("has_tiff", &has_tiff, "Get tiff read/write support status"); diff --git a/src/paths.py.in b/src/paths.py.in new file mode 100644 index 000000000..253fcd011 --- /dev/null +++ b/src/paths.py.in @@ -0,0 +1,5 @@ +import os +mapniklibpath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "lib") +inputpluginspath = os.path.join(mapniklibpath, 'mapnik', 'input') +fontscollectionpath = os.path.join(mapniklibpath, 'mapnik', 'fonts') +__all__ = [mapniklibpath,inputpluginspath,fontscollectionpath] diff --git a/test/data b/test/data index 99da07d5e..dd0c41c3f 160000 --- a/test/data +++ b/test/data @@ -1 +1 @@ -Subproject commit 99da07d5e76ccf5978ef0a380bf5f631f9088584 +Subproject commit dd0c41c3f9f5dc98291a727af00bb42734d2a8c0 diff --git a/test/data-visual b/test/data-visual index e040c3d9c..1f20cf257 160000 --- a/test/data-visual +++ b/test/data-visual @@ -1 +1 @@ -Subproject commit e040c3d9c8f6bdf3319e25f42b1cf907725285c9 +Subproject commit 1f20cf257f35224d3c139a6015b1cf70814b0d24 diff --git a/test/python_tests/agg_rasterizer_integer_overflow_test.py b/test/python_tests/agg_rasterizer_integer_overflow_test.py index af705e3d8..1f984fb61 100644 --- a/test/python_tests/agg_rasterizer_integer_overflow_test.py +++ b/test/python_tests/agg_rasterizer_integer_overflow_test.py @@ -27,7 +27,7 @@ def test_that_coordinates_do_not_overflow_and_polygon_is_rendered_memory(): expected_color = mapnik.Color('white') - projection = '+init=epsg:4326' + projection = 'epsg:4326' ds = mapnik.MemoryDatasource() context = mapnik.Context() feat = mapnik.Feature.from_geojson(json.dumps(geojson), context) @@ -57,7 +57,7 @@ def test_that_coordinates_do_not_overflow_and_polygon_is_rendered_memory(): def test_that_coordinates_do_not_overflow_and_polygon_is_rendered_csv(): expected_color = mapnik.Color('white') - projection = '+init=epsg:4326' + projection = 'epsg:4326' ds = mapnik.MemoryDatasource() context = mapnik.Context() feat = mapnik.Feature.from_geojson(json.dumps(geojson), context) diff --git a/test/python_tests/datasource_test.py b/test/python_tests/datasource_test.py index 011b07cbd..8a2183abb 100644 --- a/test/python_tests/datasource_test.py +++ b/test/python_tests/datasource_test.py @@ -29,7 +29,7 @@ def test_that_datasources_exist(): @raises(RuntimeError) def test_vrt_referring_to_missing_files(): - srs = '+init=epsg:32630' + srs = 'epsg:32630' if 'gdal' in mapnik.DatasourceCache.plugin_names(): lyr = mapnik.Layer('dataraster') lyr.datasource = mapnik.Gdal( diff --git a/test/python_tests/layer_modification_test.py b/test/python_tests/layer_modification_test.py index a4af1861f..373a57618 100644 --- a/test/python_tests/layer_modification_test.py +++ b/test/python_tests/layer_modification_test.py @@ -54,8 +54,8 @@ def test_adding_datasource_to_layer(): # also note that since the srs was black it defaulted to wgs84 eq_(m.layers[0].srs, - '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') - eq_(lyr.srs, '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') + 'epsg:4326') + eq_(lyr.srs, 'epsg:4326') # now add a datasource one... ds = mapnik.Shapefile(file='../data/shp/world_merc.shp') diff --git a/test/python_tests/layer_test.py b/test/python_tests/layer_test.py index e303c0242..f096e2589 100644 --- a/test/python_tests/layer_test.py +++ b/test/python_tests/layer_test.py @@ -14,7 +14,7 @@ def test_layer_init(): l = mapnik.Layer('test') eq_(l.name, 'test') - eq_(l.srs, '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') + eq_(l.srs, 'epsg:4326') eq_(l.envelope(), mapnik.Box2d()) eq_(l.clear_label_cache, False) eq_(l.cache_features, False) diff --git a/test/python_tests/multi_tile_raster_test.py b/test/python_tests/multi_tile_raster_test.py index 6e131d41a..26fd68adc 100644 --- a/test/python_tests/multi_tile_raster_test.py +++ b/test/python_tests/multi_tile_raster_test.py @@ -16,7 +16,7 @@ def setup(): def test_multi_tile_policy(): - srs = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' + srs = 'epsg:4326' lyr = mapnik.Layer('raster') if 'raster' in mapnik.DatasourceCache.plugin_names(): lyr.datasource = mapnik.Raster( diff --git a/test/python_tests/object_test.py b/test/python_tests/object_test.py index 583a523dc..a972d416d 100644 --- a/test/python_tests/object_test.py +++ b/test/python_tests/object_test.py @@ -331,7 +331,7 @@ # eq_(m.width, 256) # eq_(m.height, 256) -# eq_(m.srs, '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') +# eq_(m.srs, 'epsg:4326') # eq_(m.base, '') # eq_(m.maximum_extent, None) # eq_(m.background_image, None) @@ -361,7 +361,7 @@ # # Map initialization from string # def test_map_init_from_string(): -# map_string = ''' +# map_string = ''' #