diff --git a/.flake8 b/.flake8 index f340bac1ac9..84c3826b32c 100644 --- a/.flake8 +++ b/.flake8 @@ -20,8 +20,8 @@ per-file-ignores = # F841 local variable assigned to but never used # E741 ambiguous variable name 'l' __init__.py: F401, F403 - lib/init/grass.py: E501, E722, F821, F841, W605 - utils/mkrest.py: E501, W605 + lib/init/grass.py: E722, F821, F841, W605 + utils/mkrest.py: W605 utils/gitlog2changelog.py: E722, E712, W605 utils/g.html2man/ggroff.py: W605 man/build_check_rest.py: F403, F405 @@ -36,98 +36,87 @@ per-file-ignores = man/build_keywords.py: F403, F405, E722 man/build_topics.py: F403, F405, E722 man/build_html.py: E501 - man/build_rest.py: E501 - imagery/i.atcorr/create_iwave.py: E501, F632, F821, W293 + imagery/i.atcorr/create_iwave.py: F632, F821, W293 doc/python/raster_example_ctypes.py: F403, F405 doc/python/vector_example_ctypes.py: F403, F405 doc/python/m.distance.py: F403, F405, E501 doc/gui/wxpython/example/dialogs.py: F401 - doc/gui/wxpython/example/g.gui.example.py: E501 - locale/grass_po_stats.py: E122, E128, E231, E401, E501, E722, E741 - gui/scripts/d.rast3d.py: E501 + locale/grass_po_stats.py: E122, E128, E231, E401, E722, E741 gui/scripts/d.wms.py: E501 - gui/wxpython/core/debug.py: E501 - gui/wxpython/core/gcmd.py: E402, E501 - gui/wxpython/core/giface.py: E501 + gui/wxpython/core/gcmd.py: E402 gui/wxpython/core/gthread.py: F841 gui/wxpython/core/gconsole.py: E722, W605 gui/wxpython/core/globalvar.py: W605 - gui/wxpython/core/toolboxes.py: E722, E501 + gui/wxpython/core/toolboxes.py: E722 gui/wxpython/core/utils.py: E722, F841, W605 - gui/wxpython/core/workspace.py: E722, E501 - gui/wxpython/core/render.py: E722, F841, E501 - gui/wxpython/core/ws.py: F841, E501 + gui/wxpython/core/workspace.py: E722 + gui/wxpython/core/render.py: E722, F841 + gui/wxpython/core/ws.py: F841 gui/wxpython/core/settings.py: E722 gui/wxpython/core/watchdog.py: E402 - gui/wxpython/datacatalog/tree.py: E731, E402, E501 - gui/wxpython/dbmgr/base.py: E501, E722, F841 - gui/wxpython/dbmgr/dialogs.py: E501, F841, E722 - gui/wxpython/dbmgr/sqlbuilder.py: E501, E722, F841 - gui/wxpython/dbmgr/manager.py: E501, E722 + gui/wxpython/datacatalog/tree.py: E731, E402 + gui/wxpython/dbmgr/base.py: E722, F841 + gui/wxpython/dbmgr/dialogs.py: F841, E722 + gui/wxpython/dbmgr/sqlbuilder.py: E722, F841 + gui/wxpython/dbmgr/manager.py: E722 gui/wxpython/dbmgr/vinfo.py: F841 - gui/wxpython/docs/wxgui_sphinx/conf.py: E402, E501 + gui/wxpython/docs/wxgui_sphinx/conf.py: E402, W291 gui/wxpython/gcp/g.gui.gcp.py: F841 - gui/wxpython/gcp/manager.py: E501, F841, E722 + gui/wxpython/gcp/manager.py: F841, E722 gui/wxpython/gcp/mapdisplay.py: F841 - gui/wxpython/gmodeler/*: E501 gui/wxpython/gui_core/*: F841, E266, E722, W605 - gui/wxpython/gui_core/dialogs.py: E501, E722, F841, W605 - gui/wxpython/gui_core/forms.py: E501, E722, F841 - gui/wxpython/gui_core/ghelp.py: E501, E722 - gui/wxpython/gui_core/gselect.py: E501, F841, E266, E722 - gui/wxpython/gui_core/preferences.py: E501, E266, F841 - gui/wxpython/gui_core/treeview.py: E501, F841 - gui/wxpython/gui_core/widgets.py: E501, F841, E722, E266 - gui/wxpython/image2target/*: F841, E722, E265, E501 - gui/wxpython/iscatt/*: F841, E722, E741, F405, F403, E501 - gui/wxpython/lmgr/giface.py: E501, E741 - gui/wxpython/lmgr/frame.py: F841, E722, W605, E501 + gui/wxpython/gui_core/dialogs.py: E722, F841, W605 + gui/wxpython/gui_core/forms.py: E722, F841 + gui/wxpython/gui_core/ghelp.py: E722 + gui/wxpython/gui_core/gselect.py: F841, E266, E722 + gui/wxpython/gui_core/preferences.py: E266, F841 + gui/wxpython/gui_core/treeview.py: F841 + gui/wxpython/gui_core/widgets.py: F841, E722, E266 + gui/wxpython/image2target/*: F841, E722, E265 + gui/wxpython/image2target/g.gui.image2target.py: E501, E265, F841 + gui/wxpython/iscatt/*: F841, E722, E741, F405, F403 + gui/wxpython/lmgr/giface.py: E741 + gui/wxpython/lmgr/frame.py: F841, E722, W605 # layertree still includes some formatting issues (it is ignored by Black) - gui/wxpython/lmgr/layertree.py: E722, E266, W504, E225, E501 + gui/wxpython/lmgr/layertree.py: E722, E266, W504, E225 gui/wxpython/lmgr/workspace.py: F841 - gui/wxpython/modules/*: F841, E722, W605, E501 - gui/wxpython/nviz/*: F841, E266, E722, W605, F403, F405, E501 - gui/wxpython/photo2image/*: F841, E722, E265, E501 - gui/wxpython/psmap/*: F841, E266, E722, F405, F403, E501 - gui/wxpython/vdigit/*: F841, E722, E741, F405, F403, E501 - gui/wxpython/vnet/*: F841, E501 + gui/wxpython/modules/*: F841, E722, W605 + gui/wxpython/nviz/*: F841, E266, E722, W605, F403, F405 + gui/wxpython/photo2image/*: F841, E722, E265 + gui/wxpython/photo2image/g.gui.photo2image.py: E501, F841 + gui/wxpython/psmap/*: F841, E266, E722, F405, F403 + gui/wxpython/vdigit/*: F841, E722, E741, F405, F403 + gui/wxpython/vnet/*: F841 gui/wxpython/wxgui.py: F841 gui/wxpython/animation/g.gui.animation.py: E501 gui/wxpython/animation/mapwindow.py: F841 - gui/wxpython/animation/provider.py: F841, E501 - gui/wxpython/animation/temporal_manager.py: E501 - gui/wxpython/tplot/frame.py: F841, E722 + gui/wxpython/animation/provider.py: F841 + gui/wxpython/tplot/frame.py: F841, E722, E741 gui/wxpython/tplot/g.gui.tplot.py: E501 gui/wxpython/rdigit/g.gui.rdigit.py: F841 - gui/wxpython/rdigit/toolbars.py: E501 - gui/wxpython/iclass/dialogs.py: E741, E501 + gui/wxpython/iclass/dialogs.py: E741 gui/wxpython/iclass/digit.py: F405, F403 - gui/wxpython/iclass/frame.py: F405, F403, E501 + gui/wxpython/iclass/frame.py: F405, F403 gui/wxpython/iclass/g.gui.iclass.py: E501 gui/wxpython/iclass/statistics.py: F841, F405, F403 - gui/wxpython/wxplot/dialogs.py: E501 gui/wxpython/wxplot/histogram.py: E722 gui/wxpython/wxplot/profile.py: F841, E722 gui/wxpython/wxplot/base.py: F841, E722 - gui/wxpython/wxplot/scatter.py: E501 - gui/wxpython/location_wizard/dialogs.py: F841, E501 + gui/wxpython/location_wizard/dialogs.py: F841 gui/wxpython/location_wizard/wizard.py: E722 - gui/wxpython/mapdisp/frame.py: E501 - gui/wxpython/mapdisp/main.py: E722, E501 + gui/wxpython/mapdisp/main.py: E722 gui/wxpython/mapdisp/test_mapdisp.py: E501 - gui/wxpython/mapdisp/toolbars.py: E501 - gui/wxpython/mapdisp/statusbar.py: F841, E501 + gui/wxpython/mapdisp/statusbar.py: F841 gui/wxpython/mapswipe/g.gui.mapswipe.py: E501 - gui/wxpython/mapwin/base.py: E722, E501 - gui/wxpython/mapwin/buffered.py: E722, E501 - gui/wxpython/mapwin/decorations.py: E501 + gui/wxpython/mapwin/base.py: E722 + gui/wxpython/mapwin/buffered.py: E722 gui/wxpython/mapwin/graphics.py: E722 - gui/wxpython/startup/locdownload.py: E722, E402, E501 - gui/wxpython/timeline/g.gui.timeline.py: E501 - gui/wxpython/tools/build_modules_xml.py: E722, E501 + gui/wxpython/startup/locdownload.py: E722, E402 + gui/wxpython/timeline/g.gui.timeline.py: E501, E741 + gui/wxpython/timeline/frame.py: E741 + gui/wxpython/tools/build_modules_xml.py: E722 gui/wxpython/web_services/cap_interface.py: E501 - gui/wxpython/web_services/dialogs.py: E501 - gui/wxpython/web_services/widgets.py: F841, E741, W605, E402, E501 + gui/wxpython/web_services/widgets.py: F841, E741, W605, E402 gui/wxpython/rlisetup/frame.py: E741 gui/wxpython/rlisetup/sampling_frame.py: F841 gui/wxpython/rlisetup/wizard.py: E722, E741 @@ -138,57 +127,43 @@ per-file-ignores = python/grass/pydispatch/saferef.py: F821 # C wrappers call libgis.G_gisinit before importing other modules. # TODO: Is this really needed? - python/grass/pygrass/vector/__init__.py: E402, - python/grass/pygrass/raster/__init__.py: E402, - python/grass/gunittest/*.py: E501 # These are mainly just todo comments - python/grass/gunittest/gmodules.py: E501, W605 + python/grass/pygrass/vector/__init__.py: E402 + python/grass/pygrass/raster/__init__.py: E402 + python/grass/gunittest/gmodules.py: W605 + python/grass/gunittest/invoker.py: E721 python/grass/pygrass/vector/geometry.py: W605 - python/grass/pygrass/vector/table.py: E501 - python/grass/pygrass/vector/__init__.py: E501, E402 - python/grass/pygrass/modules/interface/*.py: E501, F401 - python/grass/pygrass/modules/interface/module.py: E501, W605 - python/grass/pygrass/modules/interface/parameter.py: E501, W605 - python/grass/pygrass/modules/grid/*.py: E501, F401 - python/grass/pygrass/raster/*.py: E501 + python/grass/pygrass/vector/__init__.py: E402 + python/grass/pygrass/modules/interface/*.py: F401 + python/grass/pygrass/modules/interface/module.py: W605 + python/grass/pygrass/modules/interface/parameter.py: W605 + python/grass/pygrass/modules/grid/*.py: F401 python/grass/pygrass/raster/rowio.py: E741 - python/grass/pygrass/rpc/__init__.py: E501, F401, F403 - python/grass/pygrass/utils.py: E402, E501 - python/grass/script/db.py: E501 + python/grass/pygrass/raster/category.py: E721 + python/grass/pygrass/rpc/__init__.py: F401, F403 + python/grass/pygrass/utils.py: E402 python/grass/script/task.py: W605 - python/grass/script/vector.py: E501 # Long doctest lines which need review anyway - python/grass/temporal/abstract_map_dataset.py: E501 - python/grass/temporal/abstract_space_time_dataset.py: W605, E501, F841, E722 - python/grass/temporal/aggregation.py: E501 - python/grass/temporal/base.py: E501 - python/grass/temporal/c_libraries_interface.py: E501, F841, E722 - python/grass/temporal/core.py: E501, E722 - python/grass/temporal/datetime_math.py: E501, F841, E722 - python/grass/temporal/list_stds.py: E501 - python/grass/temporal/metadata.py: E501 + python/grass/temporal/abstract_space_time_dataset.py: W605, F841, E722 + python/grass/temporal/c_libraries_interface.py: F841, E722 + python/grass/temporal/core.py: E722 + python/grass/temporal/datetime_math.py: F841, E722 python/grass/temporal/open_stds.py: F841 - python/grass/temporal/register.py: E501 - python/grass/temporal/space_time_datasets.py: E501 - python/grass/temporal/spatial_extent.py: E501 - python/grass/temporal/spatial_topology_dataset_connector.py: E501, E722 - python/grass/temporal/spatio_temporal_relationships.py: E501 - python/grass/temporal/temporal_algebra.py: E741, E501, F841, E722 - python/grass/temporal/temporal_extent.py: E501 - python/grass/temporal/temporal_granularity.py: E501, F841, E722 - python/grass/temporal/temporal_operator.py: E501 + python/grass/temporal/spatial_topology_dataset_connector.py: E722 + python/grass/temporal/temporal_algebra.py: E741, F841, E722 + python/grass/temporal/temporal_granularity.py: F841, E722 python/grass/temporal/temporal_raster_algebra.py: E741 - python/grass/temporal/temporal_raster_base_algebra.py: E501, F841, E722 + python/grass/temporal/temporal_raster_base_algebra.py: F841, E722 python/grass/temporal/temporal_raster3d_algebra.py: E741 - python/grass/temporal/temporal_topology_dataset_connector.py: E501, E722 - python/grass/temporal/temporal_vector_algebra.py: E741, E501, F841 - python/grass/temporal/univar_statistics.py: E501 + python/grass/temporal/temporal_topology_dataset_connector.py: E722 + python/grass/temporal/temporal_vector_algebra.py: E741, F841 + python/grass/temporal/univar_statistics.py: E231 # Current benchmarks/tests are changing sys.path before import. # Possibly, a different approach should be taken there anyway. - python/grass/pygrass/tests/benchmark.py: E501, E402, F401, F821 + python/grass/pygrass/tests/benchmark.py: E402, F401, F821 # Configuration file for Sphinx: # Ignoring import/code mix and line length. - python/grass/docs/conf.py: E402, E501, + python/grass/docs/conf.py: E402 # Files not managed by Black - python/grass/imaging/images2gif.py: E226, E501 + python/grass/imaging/images2gif.py: E226 # Unused imports in init files # F401 imported but unused # F403 star import used; unable to detect undefined names @@ -196,27 +171,25 @@ per-file-ignores = python/grass/*/*/__init__.py: F401, F403 python/grass/*/*/*/__init__.py: F401, F403 # E402 module level import not at top of file - scripts/d.polar/d.polar.py: F841, E501 - scripts/r.in.wms/wms_gdal_drv.py: F841, E722, E501 - scripts/r.in.wms/wms_cap_parsers.py: F841, E741, E501 - scripts/r.in.wms/wms_drv.py: E402, E722, E501 - scripts/r.in.wms/srs.py: E722, E501 + scripts/d.polar/d.polar.py: F841 + scripts/r.in.wms/wms_gdal_drv.py: F841, E722 + scripts/r.in.wms/wms_cap_parsers.py: F841, E741 + scripts/r.in.wms/wms_drv.py: E402, E722 + scripts/r.in.wms/srs.py: E722 scripts/r.semantic.label/r.semantic.label.py: F841, E501 - scripts/v.report/v.report.py: F841, E501 + scripts/v.report/v.report.py: F841, E721 scripts/db.out.ogr/db.out.ogr.py: F841 scripts/g.extension/g.extension.py: F841, E722, E501 - scripts/r.unpack/r.unpack.py: E501 scripts/v.unpack/v.unpack.py: F841, E722, E501 scripts/v.import/v.import.py: F841, E722, E501 scripts/db.univar/db.univar.py: E741, E501 scripts/d.rast.leg/d.rast.leg.py: E741 - scripts/d.frame/d.frame.py: E722, E501 + scripts/d.frame/d.frame.py: E722 scripts/i.pansharpen/i.pansharpen.py: E722, E501 - scripts/r.in.srtm/r.in.srtm.py: E722, E501 - scripts/r.fillnulls/r.fillnulls.py: E722, E501 - scripts/d.rast.edit/d.rast.edit.py: E722, E501 + scripts/r.in.srtm/r.in.srtm.py: E722 + scripts/r.fillnulls/r.fillnulls.py: E722 + scripts/d.rast.edit/d.rast.edit.py: E722 scripts/v.what.strds/v.what.strds.py: E722, E501 - scripts/i.in.spotvgt/i.in.spotvgt.py: E501 # Line too long (esp. module interface definitions) scripts/*/*.py: E501 # local variable 'column' is assigned to but never used diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 144b415cb39..57ad644c0b9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,36 +7,35 @@ assignees: '' --- -**Describe the bug** -A clear and concise description of what the bug is. +## Describe the bug + -**To Reproduce** -Steps to reproduce the behavior: +## To reproduce + -**Expected behavior** -A clear and concise description of what you expected to happen. +## Expected behavior + -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**System description (please complete the following information):** +## Screenshots + +## System description + +--> -**Additional context** -Add any other context about the problem here. +## Additional context + diff --git a/.github/actions/create-upload-suggestions/action.yml b/.github/actions/create-upload-suggestions/action.yml index 858263d8588..7d105a5fbd4 100644 --- a/.github/actions/create-upload-suggestions/action.yml +++ b/.github/actions/create-upload-suggestions/action.yml @@ -1,3 +1,4 @@ +--- name: "Create and upload suggestions" description: "Creates a file containing changes applied by a tool" author: echoix @@ -176,7 +177,7 @@ runs: echo "diff-file-name=${INPUT_DIFF_FILE_NAME}" >> "${GITHUB_OUTPUT}" env: INPUT_DIFF_FILE_NAME: ${{ steps.tool-name-safe.outputs.diff-file-name }} - - uses: actions/upload-artifact@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2 + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 id: upload-diff if: >- ${{ (steps.files_changed.outputs.files_changed == 'true') && @@ -199,7 +200,7 @@ runs: echo 'Suggestions can only be added near to lines changed in this PR.' echo 'If any fixes can be added as code suggestions, they will be added shortly from another workflow.' } >> "${GITHUB_STEP_SUMMARY}" - - uses: actions/upload-artifact@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2 + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 id: upload-changes if: >- ${{ always() && @@ -217,7 +218,9 @@ runs: run: | { echo '' - echo 'All fixed files are included in the '"${FORMATTED_URL}"' artifact. This artifact can be downloaded and copied to the repository to replace unformatted files with the formatted files.' + echo 'All fixed files are included in the '"${FORMATTED_URL}"' artifact. \ + This artifact can be downloaded and copied to the repository to replace \ + unformatted files with the formatted files.' } >> "${GITHUB_STEP_SUMMARY}" env: FORMATTED_URL: >- diff --git a/.github/labeler.yml b/.github/labeler.yml index 2073e935f24..d6caa447e2e 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -111,24 +111,24 @@ docker: - .dockerignore docs: -- all: - - changed-files: - - any-glob-to-any-file: - - doc/** - - man/** - - '**/*.md' - - '**/*.rst' - - '**/*.html' - - '**/*.dox' - - '**/*.png' - - '**.cff' - - CITING - - CHANGES - - AUTHORS - - NEWS - - TODO - - all-globs-to-all-files: - - '!doc/development/rfc/**' + - all: + - changed-files: + - any-glob-to-any-file: + - doc/** + - man/** + - '**/*.md' + - '**/*.rst' + - '**/*.html' + - '**/*.dox' + - '**/*.png' + - '**.cff' + - CITING + - CHANGES + - AUTHORS + - NEWS + - TODO + - all-globs-to-all-files: + - '!doc/development/rfc/**' RFC: - changed-files: - any-glob-to-any-file: @@ -141,14 +141,14 @@ translation: Python: - changed-files: - any-glob-to-any-file: - - '**/*.py' - - '**/pyproject.toml' + - '**/*.py' + - '**/pyproject.toml' notebook: - changed-files: - any-glob-to-any-file: - - '**/*.ipynb' - - doc/notebooks/** - - python/grass/jupyter/** + - '**/*.ipynb' + - doc/notebooks/** + - python/grass/jupyter/** C: - changed-files: - any-glob-to-any-file: '**/*.c' diff --git a/.github/workflows/additional_checks.yml b/.github/workflows/additional_checks.yml index 180d8c23ab4..f63c96cedb4 100644 --- a/.github/workflows/additional_checks.yml +++ b/.github/workflows/additional_checks.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Checkout repository contents - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 with: fetch-depth: 31 diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index 0cf81068b2b..0de351ef034 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -16,7 +16,7 @@ jobs: name: Formatting Check runs-on: ubuntu-latest steps: - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 with: persist-credentials: false - uses: DoozyX/clang-format-lint-action@11b773b1598aa4ae3b32f023701bca5201c3817d # v0.17 diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml new file mode 100644 index 00000000000..5f11fa7e295 --- /dev/null +++ b/.github/workflows/cmake.yml @@ -0,0 +1,91 @@ +# inspired by "build GDAL library and to run test with CMake" +# from https://github.com/OSGeo/gdal/blob/master/.github/workflows/cmake_builds.yml + +--- +name: CMake + +on: + push: + paths-ignore: + - 'doc/**' + branches: + - main + - releasebranch_* + pull_request: + paths-ignore: + - 'doc/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +env: + CMAKE_UNITY_BUILD: OFF + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + + build-cmake: + runs-on: ubuntu-20.04 + env: + CMAKE_OPTIONS: -DPython_LOOKUP_VERSION=3.8 -DUSE_CCACHE=ON + cache-name: cmake-ubuntu-20.04 + steps: + - name: Checkout GRASS + uses: actions/checkout@v4.1.1 + - name: Setup cache + uses: actions/cache@v4.0.2 + id: cache + with: + path: ${{ github.workspace }}/.ccache + key: "${{ env.cache-name }}-${{ runner.os }}-${{ github.base_ref }}\ + ${{ github.ref_name }}-${{ github.run_id }}" + restore-keys: | + ${{ env.cache-name }}-${{ runner.os }}-${{ github.base_ref }} + ${{ env.cache-name }}-${{ runner.os }} + #- name: Install CMake 3.16.0 + #run: | + #cd ${GITHUB_WORKSPACE} + #wget https://github.com/Kitware/CMake/releases/download/v3.16.0/cmake-3.16.0-Linux-x86_64.tar.gz + #tar xzf cmake-3.16.0-Linux-x86_64.tar.gz + #echo "CMAKE_DIR=$GITHUB_WORKSPACE/cmake-3.16.0-Linux-x86_64/bin" >> $GITHUB_ENV + #echo "$GITHUB_WORKSPACE/cmake-3.16.0-Linux-x86_64/bin" >> $GITHUB_PATH + - run: | + cmake --version + - name: Install dependencies + run: | + sudo add-apt-repository -y ppa:ubuntugis/ubuntugis-unstable + sudo apt-get update + sudo apt-get install -y -q build-essential \ + flex make bison gcc libgcc1 g++ ccache \ + python3 python3-dev \ + python3-opengl python3-wxgtk4.0 \ + python3-dateutil libgsl-dev python3-numpy \ + wx3.0-headers wx-common libwxgtk3.0-gtk3-dev \ + libwxbase3.0-dev libbz2-dev zlib1g-dev gettext \ + libtiff5-dev libpnglite-dev libcairo2 libcairo2-dev \ + sqlite3 libsqlite3-dev \ + libpq-dev libreadline6-dev libfreetype6-dev \ + libfftw3-3 libfftw3-dev \ + libboost-thread-dev libboost-program-options-dev libpdal-dev\ + subversion libzstd-dev checkinstall \ + libglu1-mesa-dev libxmu-dev \ + ghostscript wget -y make ccache g++ ninja-build + #- run: python -m pip install ninja + - name: Configure ccache + run: | + echo CCACHE_BASEDIR=$PWD >> ${GITHUB_ENV} + echo CCACHE_DIR=$PWD/.ccache >> ${GITHUB_ENV} + echo CCACHE_MAXSIZE=250M >> ${GITHUB_ENV} + ccache -z + working-directory: ${{ github.workspace }} + - name: Configure + run: | + cmake ${CMAKE_OPTIONS} -S $GITHUB_WORKSPACE -B $GITHUB_WORKSPACE/build -G Ninja + - name: Build + run: | + cmake --build $GITHUB_WORKSPACE/build --verbose -j$(nproc) + - name: ccache statistics + run: ccache -s diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9a97d72c02e..49c6a473ccd 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -6,8 +6,6 @@ on: branches: - main pull_request: - branches: - - main paths-ignore: - '**/*.html' - '**/*.md' @@ -42,7 +40,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Set up Python uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: @@ -54,9 +52,11 @@ jobs: sudo apt-get install -y wget git gawk findutils xargs -a <(awk '! /^ *(#|$)/' ".github/workflows/apt.txt") -r -- \ sudo apt-get install -y --no-install-recommends --no-install-suggests + - uses: rui314/setup-mold@6bebc01caac32fb5251ee64f60cea0322d0e6574 # v1 + if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL - uses: github/codeql-action/init@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 + uses: github/codeql-action/init@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -81,6 +81,6 @@ jobs: run: .github/workflows/build_ubuntu-22.04.sh "${HOME}/install" - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 + uses: github/codeql-action/analyze@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index d8bdfefbb33..fe8fee66507 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-22.04 if: github.repository == 'OSGeo/grass' steps: - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Get dependencies run: | diff --git a/.github/workflows/create_release_draft.yml b/.github/workflows/create_release_draft.yml index 4a1bdfb0c94..8eda136ea5a 100644 --- a/.github/workflows/create_release_draft.yml +++ b/.github/workflows/create_release_draft.yml @@ -28,7 +28,7 @@ jobs: contents: write steps: - name: Checks-out repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 with: ref: ${{ github.ref }} fetch-depth: 0 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index e8616b01718..6dda30de372 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -49,7 +49,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 with: fetch-depth: 0 - name: Docker meta diff --git a/.github/workflows/gcc.yml b/.github/workflows/gcc.yml index a7e1963bd16..c86bc378602 100644 --- a/.github/workflows/gcc.yml +++ b/.github/workflows/gcc.yml @@ -35,7 +35,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Get dependencies run: | sudo apt-get update -y diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 9dd0b1a9742..9c0598af850 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -38,7 +38,7 @@ jobs: /usr/bin/sudo /usr/bin/find /usr/local /opt/homebrew -mindepth 1 -maxdepth 1 \ -type f -print -delete hash -r - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Setup Mamba uses: mamba-org/setup-micromamba@422500192359a097648154e8db4e39bdb6c6eed7 # v1.8.1 with: @@ -74,7 +74,7 @@ jobs: nc_spm_full_v2alpha2.tar.gz" - name: Make HTML test report available if: ${{ always() }} - uses: actions/upload-artifact@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: testreport-macOS path: testreport diff --git a/.github/workflows/osgeo4w.yml b/.github/workflows/osgeo4w.yml index e8bfecc532b..49f91df5823 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -32,7 +32,7 @@ jobs: run: | git config --global core.autocrlf false git config --global core.eol lf - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - uses: msys2/setup-msys2@cc11e9188b693c2b100158c3322424c4cc1dadea # v2.22.0 with: path-type: inherit diff --git a/.github/workflows/periodic_update.yml b/.github/workflows/periodic_update.yml index 4b8cd94580b..c8c9d5d3434 100644 --- a/.github/workflows/periodic_update.yml +++ b/.github/workflows/periodic_update.yml @@ -21,7 +21,7 @@ jobs: - name: Create URL to the run output id: vars run: echo "run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_OUTPUT - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: "Check that autoconf scripts are up-to-date:" run: | rm -f config.guess config.sub @@ -33,7 +33,7 @@ jobs: run: git status --ignored - name: Create Pull Request id: cpr - uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83 # v6.0.4 + uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e # v6.0.5 with: commit-message: "config.guess + config.sub: updated from http://git.savannah.gnu.org/cgit/config.git/plain/" branch: periodic/update-configure diff --git a/.github/workflows/post-pr-reviews.yml b/.github/workflows/post-pr-reviews.yml index 9bc2997c076..7bfa9b9091f 100644 --- a/.github/workflows/post-pr-reviews.yml +++ b/.github/workflows/post-pr-reviews.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Create a .git directory needed by reviewdog run: git init - - uses: actions/download-artifact@8caf195ad4b1dee92908e23f56eeb0696f1dd42d # v4.1.5 + - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 id: diff continue-on-error: true with: diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index caa530f90e1..62dbe8c3014 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -8,8 +8,6 @@ on: - releasebranch_* pull_request: branches: - - main - - releasebranch_* jobs: pytest: @@ -29,9 +27,12 @@ jobs: fail-fast: true runs-on: ${{ matrix.os }} + env: + FORCE_COLOR: 1 # for software including pip: https://force-color.org/ + CLICOLOR_FORCE: 1 # for other software including ninja: https://bixense.com/clicolors/ steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Set up Python uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 @@ -46,6 +47,8 @@ jobs: xargs -a <(awk '! /^ *(#|$)/' ".github/workflows/apt.txt") -r -- \ sudo apt-get install -y --no-install-recommends --no-install-suggests + - uses: rui314/setup-mold@6bebc01caac32fb5251ee64f60cea0322d0e6574 # v1 + - name: Install Python dependencies run: | python -m pip install --upgrade pip @@ -75,7 +78,7 @@ jobs: run: | export PYTHONPATH=`grass --config python_path`:$PYTHONPATH export LD_LIBRARY_PATH=$HOME/install/grass84/lib:$LD_LIBRARY_PATH - pytest --numprocesses auto . + pytest --verbose --color=yes --durations=0 --durations-min=0.5 --numprocesses auto -ra . - name: Print installed versions if: always() diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index ab44d3abd8a..e5f6cb80af6 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -7,9 +7,6 @@ on: - main - releasebranch_* pull_request: - branches: - - main - - releasebranch_* jobs: python-checks: @@ -29,7 +26,7 @@ jobs: - os: ubuntu-22.04 python-version: "3.10" min-python-version: "3.7" - black-version: "23.1.0" + black-version: "24.4.0" flake8-version: "3.9.2" pylint-version: "2.12.2" bandit-version: "1.7.8" @@ -49,7 +46,7 @@ jobs: echo Pylint: ${{ matrix.pylint-version }} echo Bandit: ${{matrix.bandit-version}} - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Set up Python uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 @@ -60,7 +57,7 @@ jobs: run: python -m pip install --upgrade pip - name: Install Black only - run: pip install black==${{ matrix.black-version }} + run: pip install black[jupyter]==${{ matrix.black-version }} - name: Run Black run: black . @@ -102,13 +99,13 @@ jobs: bandit -c pyproject.toml -iii -r . -f sarif -o bandit.sarif --exit-zero - name: Upload Bandit Scan Results - uses: actions/upload-artifact@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: bandit.sarif path: bandit.sarif - name: Upload SARIF File into Security Tab - uses: github/codeql-action/upload-sarif@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 + uses: github/codeql-action/upload-sarif@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3 with: sarif_file: bandit.sarif @@ -120,6 +117,7 @@ jobs: run: | echo "MAKEFLAGS=-j$(nproc)" >> $GITHUB_ENV + - uses: rui314/setup-mold@6bebc01caac32fb5251ee64f60cea0322d0e6574 # v1 - name: Build run: .github/workflows/build_${{ matrix.os }}.sh $HOME/install @@ -142,7 +140,7 @@ jobs: export PYTHONPATH=`grass --config python_path`:$PYTHONPATH export LD_LIBRARY_PATH=$HOME/install/grass84/lib:$LD_LIBRARY_PATH cd gui/wxpython - pylint --persistent=no --py-version=${{ matrix.min-python-version }} --jobs=$(nproc) * + pylint --persistent=no --py-version=${{ matrix.min-python-version }} --jobs=$(nproc) --ignore=CMakeLists.txt * - name: Run Pylint on other files using pytest run: | @@ -175,7 +173,7 @@ jobs: cp -rp dist.$ARCH/docs/html/libpython sphinx-grass - name: Make Sphinx documentation available - uses: actions/upload-artifact@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: sphinx-grass path: sphinx-grass diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml index 6712d5d9323..1cf7c414e9d 100644 --- a/.github/workflows/super-linter.yml +++ b/.github/workflows/super-linter.yml @@ -28,7 +28,7 @@ jobs: statuses: write steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 with: # super-linter needs the full git history to get the # list of files that changed across commits diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 032ba3391c7..f1e784689ac 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -61,7 +61,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Invert inclusion list to an exclusion list id: get-exclude @@ -151,7 +151,7 @@ jobs: - name: Make HTML test report available if: ${{ always() }} - uses: actions/upload-artifact@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: testreport-${{ matrix.os }}-${{ matrix.config }}-${{ matrix.extra-include }} path: testreport diff --git a/.gitignore b/.gitignore index 2cc7f3da721..a1e826ceea8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ OBJ.* locale/scriptstrings/* bin.*/* dist.*/* +.vs/* +CMakeSettings.json config.log config.status* error.log @@ -50,6 +52,7 @@ test_keyvalue_result.txt # ignore paths generated by helper tools node_modules + include/VERSION_GIT # ignore autogenerated documentation @@ -58,3 +61,6 @@ html/ latex/ lib/*/html/ lib/*/latex/ + +# ignore cmake build directory +build \ No newline at end of file diff --git a/.markdownlint.yml b/.markdownlint.yml new file mode 100644 index 00000000000..56c5c555930 --- /dev/null +++ b/.markdownlint.yml @@ -0,0 +1,3 @@ +--- + +default: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 61509b4280b..5137a2024ae 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,10 +39,11 @@ repos: rev: v0.33.0 hooks: - id: markdownlint - - repo: https://github.com/psf/black - rev: 23.1.0 + # Using this mirror lets us use mypyc-compiled black, which is about 2x faster + - repo: https://github.com/psf/black-pre-commit-mirror + rev: 24.4.0 hooks: - - id: black + - id: black-jupyter exclude: | (?x)^( python/libgrass_interface_generator/ @@ -69,7 +70,3 @@ repos: rev: v1.29.0 hooks: - id: yamllint - args: [--format, parsable, --strict, -d, - '{extends: default, rules: {truthy: disable, - line-length: {max: 120, allow-non-breakable-words: true}, - comments: {min-spaces-from-content: 1}}}'] diff --git a/.yamllint b/.yamllint new file mode 100644 index 00000000000..1b600992d0b --- /dev/null +++ b/.yamllint @@ -0,0 +1,15 @@ +--- + +extends: default + +rules: + comments: + level: error + min-spaces-from-content: 1 + document-start: + level: error + line-length: + level: error + max: 120 + allow-non-breakable-inline-mappings: true + truthy: disable diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000000..723736ebbf5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,290 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: GRASS GIS root that adds options to activate/deactivate + 3rd party libraries +COPYRIGHT: (C) 2020-2022 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +#]] + +cmake_minimum_required(VERSION 3.11) +set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) + +# if(DEFINED ENV{VCPKG_DEFAULT_TRIPLET} AND NOT DEFINED VCPKG_TARGET_TRIPLET) +# set(VCPKG_TARGET_TRIPLET "$ENV{VCPKG_DEFAULT_TRIPLET}" CACHE STRING "") +# endif() + +project(GRASS) + +set(BUILD_SHARED_LIBS ON) +# message(FATAL_ERROR "VCPKG_TARGET_TRIPLET=${VCPKG_TARGET_TRIPLET}") +if(MSVC) + if(BUILD_SHARED_LIBS) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) + endif() + + set_property(GLOBAL PROPERTY USE_FOLDERS ON) +endif() + +set(CMAKE_MODULE_PATH + "${CMAKE_SOURCE_DIR}/cmake/find_scripts;${CMAKE_SOURCE_DIR}/cmake/modules;${CMAKE_MODULE_PATH}" +) + +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() + +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 11) + set(CMAKE_C_STANDARD_REQUIRED ON) +endif() + +set(default_option_enabled ON) +if(WIN32) + set(default_option_enabled OFF) +endif() + +# Configure CCache if available +if(NOT MSVC) + option(USE_CCACHE "Use ccache" ON) + if(USE_CCACHE) + find_program(CCACHE_FOUND ccache) + if(CCACHE_FOUND) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) + message(STATUS "ccache found") + endif(CCACHE_FOUND) + endif(USE_CCACHE) +endif(NOT MSVC) + +if(USE_ALTERNATE_LINKER) + include("cmake/modules/linker.cmake") +endif() + +if(CMAKE_BUILD_TYPE) + set(grass_build_type "${CMAKE_BUILD_TYPE}") + string(TOLOWER "${grass_build_type}" grass_build_type_lc) + set(find_library_suffix "_RELEASE") + if(grass_build_type_lc STREQUAL "debug") + set(find_library_suffix "_DEBUG") + endif() +else() + set(find_library_suffix "") +endif() + +# Graphics options +option(WITH_X11 "Build with X11 support ." ${default_option_enabled}) +option(WITH_OPENGL "Build with opengl support ." ON) +option(WITH_CAIRO "Build with cairo support ." ON) +option(WITH_LIBPNG "Build with libpng support ." OFF) + +# Data storage options +option(WITH_SQLITE "Build with SQLite support" ON) +option(WITH_POSTGRES "Build with Postgres support" OFF) +option(WITH_MYSQL "Build with MySQL support" OFF) +if(WIN32) + option(WITH_ODBC "Build with ODBC support" OFF) +endif() +option(WITH_ZSTD "Build with zstd support" ON) +option(WITH_BZLIB "Build with bzlib support" OFF) + +# Command-line options +option(WITH_READLINE "Build with Readline support" OFF) + +# Language options +option(WITH_FREETYPE "Build with FreeType support" ON) +option(WITH_NLS "Build with NLS support" ${default_option_enabled}) + +# Computing options +option(WITH_FFTW "Build with FFTW support" ON) +option(WITH_BLAS "Build with BLAS support" ON) +option(WITH_LAPACK "Build with LAPACK support" ON) +option(WITH_OPENMP "Build with OpenMP support" ON) + +# Data format options +option(WITH_TIFF "Build with LibTIFF support ." ON) +option(WITH_NETCDF "Build with NetCDF support" OFF) +option(WITH_GEOS "Build with GEOS support" OFF) +option(WITH_PDAL "Build with PDAL support" ON) +option(WITH_LIBLAS "Build with libLAS support" OFF) +option(WITH_OPENDWG "Build with OpenDWG support" OFF) + +# Other options +option(WITH_LARGEFILES "Build with large file support" + ${default_option_enabled}) +option(WITH_DOCS "Build documentation" ON) +option(WITH_GUI "Build GUI" ON) + +if(APPLE) + if(POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) + endif() + set(CMAKE_MACOSX_RPATH TRUE) +endif() + +set(CMAKE_SKIP_BUILD_RPATH FALSE) +set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES + "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) +if("${isSystemDir}" STREQUAL "-1") + set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") +endif("${isSystemDir}" STREQUAL "-1") + +set(GISBASE ${CMAKE_BINARY_DIR}/gisbase) +file(TO_NATIVE_PATH "${CMAKE_SOURCE_DIR}" MODULE_TOPDIR) +file(TO_NATIVE_PATH "${GISBASE}" GISBASE_NATIVE) +file(TO_NATIVE_PATH "${GISBASE}/bin" BIN_DIR) +file(TO_NATIVE_PATH "${GISBASE}/lib" LIB_DIR) +file(TO_NATIVE_PATH "${GISBASE}/scripts" SCRIPTS_DIR) +file(TO_NATIVE_PATH "${GISBASE}/etc/config/rc" GISRC) +file(TO_NATIVE_PATH "${GISBASE}/etc/python" ETC_PYTHON_DIR) +file(TO_NATIVE_PATH "${GISBASE}/gui/wxpython" GUI_WXPYTHON_DIR) + +# Setup build locations. +if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${GISBASE}/lib) +endif() +if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${GISBASE}/lib) +endif() + +# XXX: not used for now; setup install directories +set(GISBASE_DIR "grass${GRASS_VERSION_MAJOR}${GRASS_VERSION_MINOR}") +set(GRASS_BIN_DIR "${GISBASE_DIR}/bin") +set(GRASS_LIB_DIR "${GISBASE_DIR}/lib") +set(GRASS_SCRIPTS_DIR "${GISBASE_DIR}/scripts") +set(GRASS_ETC_DIR "${GISBASE_DIR}/etc") +set(GRASS_GUI_DIR "${GISBASE_DIR}/gui") +set(GRASS_DRIVER_DIR "${GISBASE_DIR}/driver") +set(GRASS_FONTS_DIR "${GISBASE_DIR}/fonts") +set(GRASS_UTILS_DIR "${GISBASE_DIR}/utils") +set(GRASS_SHARE_DIR "${GISBASE_DIR}/share") +set(GRASS_INCLUDE_DIR "${GISBASE_DIR}/include") +set(GRASS_DOCS_DIR "${GISBASE_DIR}/docs") +set(GRASS_DEMOLOCATION_DIR "${GISBASE_DIR}/demolocation") + +include(get_host_arch) +get_host_arch(BUILD_ARCH) + +include(get_versions) +get_versions("include/VERSION" GRASS_VERSION_MAJOR GRASS_VERSION_MINOR + GRASS_VERSION_RELEASE GRASS_VERSION_DATE) + +set(GRASS_VERSION_NUMBER + ${GRASS_VERSION_MAJOR}.${GRASS_VERSION_MINOR}.${GRASS_VERSION_RELEASE}) +message(STATUS "GRASS_VERSION_NUMBER = '${GRASS_VERSION_NUMBER}'") +set(GRASS_VERSION_UPDATE_PKG "0.2") + +include(set_compiler_flags) +set_compiler_flags() +include(Configure) + +include(repo_status) +repo_status("${CMAKE_CURRENT_LIST_DIR}") + +enable_testing() + +include(check_target) +include(CheckDependentLibraries) +include(build_module) +include(build_program) +include(build_program_in_subdir) +include(build_library_in_subdir) +include(copy_python_files_in_subdir) +include(build_script_in_subdir) +include(build_gui_in_subdir) + +set(MKHTML_PY ${CMAKE_BINARY_DIR}/utils/mkhtml.py) + +if(WIN32) + set(sep "\;") + set(env_path "") +else() + set(sep ":") + set(env_path ":$ENV{PATH}") +endif() + +set(grass_env_command + ${CMAKE_COMMAND} -E env "PATH=${BIN_DIR}${sep}${SCRIPTS_DIR}${env_path}" + "PYTHONPATH=${ETC_PYTHON_DIR}${sep}${GUI_WXPYTHON_DIR}${sep}$ENV{PYTHONPATH}" + "LD_LIBRARY_PATH=${LIB_DIR}${sep}$ENV{LD_LIBRARY_PATH}" + "GISBASE=${GISBASE_NATIVE}" "GISRC=${GISRC}" "LC_ALL=C" "LANG=C" + "LANGUAGE=C" "MODULE_TOPDIR=${MODULE_TOPDIR}" + "VERSION_NUMBER=\"${GRASS_VERSION_NUMBER}\"" + "VERSION_DATE=\"${GRASS_VERSION_DATE}\"") + +set(NO_HTML_DESCR_TARGETS "g.parser;ximgview;test.raster3d.lib") +# include(Configure) +add_subdirectory(include) + +include_directories("${GISBASE}/include") +include_directories("${GISBASE}/include/grass") +if(MSVC) + include_directories("${CMAKE_SOURCE_DIR}/msvc") +endif() + +execute_process( + COMMAND ${CMAKE_COMMAND} -E echo "Creating directories in ${GISBASE}" + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/bin/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/scripts/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/demolocation/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/etc/config/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/driver/db/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/utils/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/lib/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/python/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/etc/lister/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/etc/python/grass/lib + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/gui/wxpython/xml/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/gui/icons/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/gui/images/ + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/docs/html/) + +add_subdirectory(lib) +add_subdirectory(utils) +set(modules_list) + +set(ALL_SUBDIRS + general + db + display + imagery + misc + raster + raster3d + scripts + vector + temporal + ps) + +foreach(d ${ALL_SUBDIRS}) + add_subdirectory(${d}) +endforeach() +add_custom_target( + ALL_MODULES + COMMAND ${CMAKE_COMMAND} -E echo "Building all modules" + DEPENDS ${modules_list}) + +# message(FATAL_ERROR "modules_list=${modules_list}") + +if(WITH_GUI) + add_subdirectory(gui) +endif() + +add_subdirectory(python) + +if(WITH_DOCS) + add_subdirectory(doc) + add_subdirectory(man) +endif() # WITH_DOCS + +# add_subdirectory(locale) + +# TODO: To be discussed - add_subdirectory(testsuite) - add_subdirectory(macosx) + +if(WITH_X11) + build_program_in_subdir(visualization/ximgview DEPENDS grass_gis X11) +endif() diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..0b17de48af4 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[grass-coc@osgeo.org](mailto:grass-coc@osgeo.org). +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/Dockerfile b/Dockerfile index cefa32d0656..c45d5796bfe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ ARG GUI=without -FROM ubuntu:22.04@sha256:1b8d8ff4777f36f19bfe73ee4df61e3a0b789caeff29caa019539ec7c9a57f95 as common_start +FROM ubuntu:22.04@sha256:a6d2b38300ce017add71440577d5b0a90460d0e57fd7aec21dd0d1b0761bbfb2 as common_start LABEL authors="Carmen Tawalika,Markus Neteler,Anika Weinmann,Stefan Blumentrath" LABEL maintainer="tawalika@mundialis.de,neteler@mundialis.de,weinmann@mundialis.de" diff --git a/README.md b/README.md index ce6a2ead887..c7bb195cc6b 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ [![Coverity](https://scan.coverity.com/projects/1038/badge.svg)](https://scan.coverity.com/projects/grass) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5176030.svg)](https://doi.org/10.5281/zenodo.5176030) [![Join the chat at https://gitter.im/grassgis/community](https://badges.gitter.im/grassgis/community.svg)](https://gitter.im/grassgis/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](code_of_conduct.md) ## Description diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..feef9649806 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,58 @@ +# GRASS GIS Security Policy + +## Reporting a Vulnerability + +At GRASS GIS, we take security vulnerabilities seriously. We appreciate your +efforts in responsibly disclosing any issues you may find. To report a security +vulnerability, please follow these steps: + +1. **Privately disclose the issue** by submitting a Security Advisory through + [GitHub Security](https://github.com/OSGeo/grass/security). Please do not + create publicly viewable issues for security vulnerabilities. +2. **Provide detailed information** regarding the vulnerability, including: + - Description of the vulnerability + - Steps to reproduce + - Versions affected + - Any mitigating factors +3. **Our Response**: + - Our security team will acknowledge receiving your report within 48 hours. + - We will work to validate and reproduce the issue. + - Once confirmed, we will work on a fix and release schedule. +4. **Public Disclosure**: + - We aim to release patches for vulnerabilities as soon as possible. + - We will coordinate with you regarding public disclosure, ensuring a + reasonable timeline for users to update before the details are made public. + +## Supported Versions + +Please refer to our [Release Schedule](https://trac.osgeo.org/grass/wiki/Release/Schedule) +for details on which versions are currently supported. + +## Security Measures + +- Code Review: We conduct code reviews to catch potential vulnerabilities during + code submission. +- Dependency Management: We track dependencies and update them regularly to + mitigate known security issues. +- Secure Development Practices: We use a series of security tools to detect + potential vulnerabilities in existing and newly submitted code. + +## Vulnerability Scope + +Our security policy covers vulnerabilities in the GRASS GIS core codebase, +official addons, and any official distributions provided by the GRASS GIS team. + +While packages in Linux and other unix-like distributions are out of scope of +this document, distribution maintainers traditionally do a great job in patching +their distributions for security vulnerabilities. Please, refer to a specific +distribution or package source if you are using packages for a specific software +distribution. + +## Responsible Disclosure + +We adhere to responsible disclosure practices. We appreciate your cooperation +in allowing us time to address any reported vulnerabilities before disclosing +them publicly. We ask that you refrain from disclosing any details of the +vulnerability until we have had adequate time to provide a fix. + +Thank you for helping to keep GRASS GIS secure! diff --git a/binaryInstall.src b/binaryInstall.src index c9736d7c95a..5ab008dd796 100755 --- a/binaryInstall.src +++ b/binaryInstall.src @@ -319,7 +319,7 @@ echo"" echo "Generating display font configuration file..." -GISBASE="$DESTDIR" GISRC=junk LD_LIBRARY_PATH_VAR="${DESTDIR}/lib:$LD_LIBRARY_PATH_VAR" "${DESTDIR}/bin/g.mkfontcap" -o +GISBASE="$DESTDIR" GISRC=junk LD_LIBRARY_PATH_VAR="${DESTDIR}/lib:$LD_LIBRARY_PATH_VAR" "${DESTDIR}/bin/g.mkfontcap" --overwrite echo"" diff --git a/cmake/copy_g_gui_module.cmake b/cmake/copy_g_gui_module.cmake new file mode 100644 index 00000000000..21fc99559da --- /dev/null +++ b/cmake/copy_g_gui_module.cmake @@ -0,0 +1,39 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: Copy g.gui script plus .bat file if on windows +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +-DSOURCE_DIR +-DGISBASE +-DG_NAME +-DSRC_SCRIPT_FILE +-DBINARY_DIR +#]] + +set(SCRIPT_EXT "") +if(WIN32) + set(SCRIPT_EXT ".py") +endif() + +if(WIN32) + set(PGM_NAME ${G_NAME}) + configure_file(${SOURCE_DIR}/cmake/windows_launch.bat.in + ${GISBASE}/scripts/${G_NAME}.bat @ONLY) +endif(WIN32) + +set(TMP_SCRIPT_FILE ${BINARY_DIR}/CMakeFiles/${G_NAME}${SCRIPT_EXT}) +configure_file(${SRC_SCRIPT_FILE} ${TMP_SCRIPT_FILE} COPYONLY) +file( + COPY ${TMP_SCRIPT_FILE} + DESTINATION ${GISBASE}/scripts/ + FILE_PERMISSIONS + OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE) + +file(REMOVE ${TMP_SCRIPT_FILE}) diff --git a/cmake/ctypesgen.cmake b/cmake/ctypesgen.cmake new file mode 100644 index 00000000000..3ad7bb3f3ae --- /dev/null +++ b/cmake/ctypesgen.cmake @@ -0,0 +1,66 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: Cmake building of lib/python/ctypes (TODO) +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +#]] + +set(ENV{GISRC} + "${BIN_DIR}/demolocation/.grassrc${GRASS_VERSION_MAJOR}${GRASS_VERSION_MINOR}" +) +set(ENV{GISBASE} "${BIN_DIR}") +set(ENV{PATH} "${BIN_DIR}/bin:${BIN_DIR}/scripts:$ENV{PATH}") +set(ENV{PYTHONPATH} + "${BIN_DIR}/gui/wxpython:${BIN_DIR}/etc/python:$ENV{PYTHONPATH}") +if(NOT MSVC) + set(ENV{LD_LIBRARY_PATH} "${BIN_DIR}/lib:$ENV{LD_LIBRARY_PATH}") +endif() +set(ENV{LC_ALL} C) + +set(LIBRARIES) +foreach(LIB ${LIBS}) + if(WIN32) + list(APPEND LIBRARIES "--library=${BIN_DIR}/lib/${LIB}.dll") + elseif(APPLE) + list(APPEND LIBRARIES "--library=${BIN_DIR}/lib/lib${LIB}.so") + else() + # This can be linux or unix + list(APPEND LIBRARIES "--library=${BIN_DIR}/lib/lib${LIB}.so") + endif() +endforeach() + +set(HEADERS) +foreach(HDR ${HDRS}) + list(APPEND HEADERS "${BIN_DIR}/include/grass/${HDR}") +endforeach() + +foreach(req OUT_FILE HDRS LIBS CTYPESGEN_PY COMPILER) + if(NOT DEFINED ${req} OR "${${req}}" STREQUAL "") + message(FATAL_ERROR "you must set ${req}") + endif() +endforeach() + +if(MSVC) + set(CTYPESFLAGS "${COMPILER} -E -DPACKAGE=\"grasslibs\"") +else() + set(CTYPESFLAGS + "${COMPILER} -E -DPACKAGE=\"grasslibs\" -D__GLIBC_HAVE_LONG_LONG") +endif() + +message( + STATUS + "Running ${PYTHON_EXECUTABLE} ${CTYPESGEN_PY} --cpp=${CTYPESFLAGS} --includedir=\"${BIN_DIR}/include\" --runtime-libdir=\"${BIN_DIR}/lib\" ${HEADERS} ${LIBRARIES} --output=${OUT_FILE}" +) +execute_process( + COMMAND + ${PYTHON_EXECUTABLE} ${CTYPESGEN_PY} --cpp=${CTYPESFLAGS} + --includedir="${BIN_DIR}/include" --runtime-libdir="${BIN_DIR}/lib" + ${HEADERS} ${LIBRARIES} --output=${OUT_FILE} + OUTPUT_VARIABLE ctypesgen_OV + ERROR_VARIABLE ctypesgen_EV + RESULT_VARIABLE ctypesgen_RV) + +if(ctypesgen_RV) + message(FATAL_ERROR "ctypesgen.py: ${ctypesgen_EV} \n ${ctypesgen_OV}") +endif() diff --git a/cmake/find_scripts/FindCairo.cmake b/cmake/find_scripts/FindCairo.cmake new file mode 100644 index 00000000000..c6551cb0fdc --- /dev/null +++ b/cmake/find_scripts/FindCairo.cmake @@ -0,0 +1,125 @@ +#[[ +- Try to find Cairo +Once done, this will define + + CAIRO_FOUND - system has Cairo + CAIRO_INCLUDE_DIRS - the Cairo include directories + CAIRO_LIBRARIES - link these to use Cairo + +Copyright (C) 2012 Raphael Kubo da Costa + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS +IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#]] + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_CAIRO cairo QUIET) # FIXME: After we require CMake 2.8.2 we + # can pass QUIET to this call. + +find_path( + CAIRO_INCLUDE_DIRS + NAMES cairo.h + HINTS ${PC_CAIRO_INCLUDEDIR} ${PC_CAIRO_INCLUDE_DIRS} + PATH_SUFFIXES cairo) + +find_library( + CAIRO_LIBRARY_RELEASE + NAMES cairo + HINTS ${PC_CAIRO_LIBDIR} ${PC_CAIRO_LIBRARY_DIRS}) + +find_library( + CAIRO_LIBRARY_DEBUG + NAMES cairod + HINTS ${PC_CAIRO_LIBDIR} ${PC_CAIRO_LIBRARY_DIRS}) + +set(CAIRO_LIBRARY) +if(CAIRO_LIBRARY_DEBUG) + set(CAIRO_LIBRARY ${CAIRO_LIBRARY_DEBUG}) +elseif(CAIRO_LIBRARY_RELEASE) + set(CAIRO_LIBRARY ${CAIRO_LIBRARY_RELEASE}) +endif() + +if(CAIRO_INCLUDE_DIRS) + if(EXISTS "${CAIRO_INCLUDE_DIRS}/cairo-version.h") + file(READ "${CAIRO_INCLUDE_DIRS}/cairo-version.h" CAIRO_VERSION_CONTENT) + + string(REGEX MATCH "#define +CAIRO_VERSION_MAJOR +([0-9]+)" _dummy + "${CAIRO_VERSION_CONTENT}") + set(CAIRO_VERSION_MAJOR "${CMAKE_MATCH_1}") + + string(REGEX MATCH "#define +CAIRO_VERSION_MINOR +([0-9]+)" _dummy + "${CAIRO_VERSION_CONTENT}") + set(CAIRO_VERSION_MINOR "${CMAKE_MATCH_1}") + + string(REGEX MATCH "#define +CAIRO_VERSION_MICRO +([0-9]+)" _dummy + "${CAIRO_VERSION_CONTENT}") + set(CAIRO_VERSION_MICRO "${CMAKE_MATCH_1}") + + set(CAIRO_VERSION + "${CAIRO_VERSION_MAJOR}.${CAIRO_VERSION_MINOR}.${CAIRO_VERSION_MICRO}") + endif() +endif() + +# FIXME: Should not be needed anymore once we start depending on CMake 2.8.3 +set(VERSION_OK TRUE) +if(Cairo_FIND_VERSION) + if(Cairo_FIND_VERSION_EXACT) + if("${Cairo_FIND_VERSION}" VERSION_EQUAL "${CAIRO_VERSION}") + # FIXME: Use IF (NOT ...) with CMake 2.8.2+ to get rid of the ELSE block + else() + set(VERSION_OK FALSE) + endif() + else() + if("${Cairo_FIND_VERSION}" VERSION_GREATER "${CAIRO_VERSION}") + set(VERSION_OK FALSE) + endif() + endif() +endif() + +find_path(FONTCONFIG_INCLUDE_DIR fontconfig/fontconfig.h) + +if(FONTCONFIG_INCLUDE_DIR) + set(CAIRO_INCLUDE_DIRS ${CAIRO_INCLUDE_DIRS} ${FONTCONFIG_INCLUDE_DIR}) +else() + message( + STATUS + "fontconfig/fontconfig.h was not found. \n I had to unset(CAIRO_INCLUDE_DIRS) to make find_package() fail \n " + ) + unset(CAIRO_INCLUDE_DIRS CACHE) +endif() + +find_library(FONTCONFIG_LIBRARY NAMES fontconfig) +if(FONTCONFIG_LIBRARY) + set(CAIRO_LIBRARIES ${CAIRO_LIBRARY} ${FONTCONFIG_LIBRARY}) +else() + message( + STATUS + "fontconfig library file was not found. \n I had to unset(CAIRO_LIBRARIES) to make find_package() fail \n " + ) + unset(CAIRO_LIBRARIES CACHE) +endif() + +mark_as_advanced(CAIRO_INCLUDE_DIRS CAIRO_LIBRARY CAIRO_LIBRARY_RELEASE + CAIRO_LIBRARY_DEBUG FONTCONFIG_LIBRARY FONTCONFIG_INCLUDE_DIR) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Cairo DEFAULT_MSG CAIRO_INCLUDE_DIRS + CAIRO_LIBRARIES VERSION_OK) diff --git a/cmake/find_scripts/FindFFTW-egpbos.cmake b/cmake/find_scripts/FindFFTW-egpbos.cmake new file mode 100644 index 00000000000..1861b54c19d --- /dev/null +++ b/cmake/find_scripts/FindFFTW-egpbos.cmake @@ -0,0 +1,421 @@ +# - Find the FFTW library +# +# Original version of this file: +# Copyright (c) 2015, Wenzel Jakob +# https://github.com/wjakob/layerlab/blob/master/cmake/FindFFTW.cmake, commit 4d58bfdc28891b4f9373dfe46239dda5a0b561c6 +# Modifications: +# Copyright (c) 2017, Patrick Bos +# +# Usage: +# find_package(FFTW [REQUIRED] [QUIET] [COMPONENTS component1 ... componentX] ) +# +# It sets the following variables: +# FFTW_FOUND ... true if fftw is found on the system +# FFTW_[component]_LIB_FOUND ... true if the component is found on the system (see components below) +# FFTW_LIBRARIES ... full paths to all found fftw libraries +# FFTW_[component]_LIB ... full path to one of the components (see below) +# FFTW_INCLUDE_DIRS ... fftw include directory paths +# +# The following variables will be checked by the function +# FFTW_USE_STATIC_LIBS ... if true, only static libraries are found, otherwise both static and shared. +# FFTW_ROOT ... if set, the libraries are exclusively searched +# under this path +# +# This package supports the following components: +# FLOAT_LIB +# DOUBLE_LIB +# LONGDOUBLE_LIB +# FLOAT_THREADS_LIB +# DOUBLE_THREADS_LIB +# LONGDOUBLE_THREADS_LIB +# FLOAT_OPENMP_LIB +# DOUBLE_OPENMP_LIB +# LONGDOUBLE_OPENMP_LIB +# + +# From: https://github.com/egpbos/findFFTW/tree/master + +# TODO (maybe): extend with ExternalProject download + build option +# TODO: put on conda-forge + + +if( NOT FFTW_ROOT AND DEFINED ENV{FFTWDIR} ) + set( FFTW_ROOT $ENV{FFTWDIR} ) +endif() + +# Check if we can use PkgConfig +find_package(PkgConfig) + +#Determine from PKG +if( PKG_CONFIG_FOUND AND NOT FFTW_ROOT ) + pkg_check_modules( PKG_FFTW QUIET "fftw3" ) +endif() + +#Check whether to search static or dynamic libs +set( CMAKE_FIND_LIBRARY_SUFFIXES_SAV ${CMAKE_FIND_LIBRARY_SUFFIXES} ) + +if( ${FFTW_USE_STATIC_LIBS} ) + set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX} ) +else() + set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV} ) +endif() + +if( FFTW_ROOT ) + # find libs + + find_library( + FFTW_DOUBLE_LIB + NAMES "fftw3" libfftw3-3 + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_DOUBLE_THREADS_LIB + NAMES "fftw3_threads" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_DOUBLE_OPENMP_LIB + NAMES "fftw3_omp" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_DOUBLE_MPI_LIB + NAMES "fftw3_mpi" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_FLOAT_LIB + NAMES "fftw3f" libfftw3f-3 + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_FLOAT_THREADS_LIB + NAMES "fftw3f_threads" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_FLOAT_OPENMP_LIB + NAMES "fftw3f_omp" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_FLOAT_MPI_LIB + NAMES "fftw3f_mpi" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_LONGDOUBLE_LIB + NAMES "fftw3l" libfftw3l-3 + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_LONGDOUBLE_THREADS_LIB + NAMES "fftw3l_threads" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_LONGDOUBLE_OPENMP_LIB + NAMES "fftw3l_omp" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_LONGDOUBLE_MPI_LIB + NAMES "fftw3l_mpi" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + #find includes + find_path(FFTW_INCLUDE_DIRS + NAMES "fftw3.h" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "include" + NO_DEFAULT_PATH + ) + +else() + + find_library( + FFTW_DOUBLE_LIB + NAMES "fftw3" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_library( + FFTW_DOUBLE_THREADS_LIB + NAMES "fftw3_threads" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_library( + FFTW_DOUBLE_OPENMP_LIB + NAMES "fftw3_omp" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_library( + FFTW_DOUBLE_MPI_LIB + NAMES "fftw3_mpi" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_library( + FFTW_FLOAT_LIB + NAMES "fftw3f" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_library( + FFTW_FLOAT_THREADS_LIB + NAMES "fftw3f_threads" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_library( + FFTW_FLOAT_OPENMP_LIB + NAMES "fftw3f_omp" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_library( + FFTW_FLOAT_MPI_LIB + NAMES "fftw3f_mpi" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_library( + FFTW_LONGDOUBLE_LIB + NAMES "fftw3l" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_library( + FFTW_LONGDOUBLE_THREADS_LIB + NAMES "fftw3l_threads" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_library(FFTW_LONGDOUBLE_OPENMP_LIB + NAMES "fftw3l_omp" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_library(FFTW_LONGDOUBLE_MPI_LIB + NAMES "fftw3l_mpi" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_path(FFTW_INCLUDE_DIRS + NAMES "fftw3.h" + PATHS ${PKG_FFTW_INCLUDE_DIRS} ${INCLUDE_INSTALL_DIR} + ) + +endif( FFTW_ROOT ) + +#--------------------------------------- components + +if (FFTW_DOUBLE_LIB) + set(FFTW_DOUBLE_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_LIB}) + add_library(FFTW::Double INTERFACE IMPORTED) + set_target_properties(FFTW::Double + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_LIB}" + ) +else() + set(FFTW_DOUBLE_LIB_FOUND FALSE) +endif() + +if (FFTW_FLOAT_LIB) + set(FFTW_FLOAT_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_LIB}) + add_library(FFTW::Float INTERFACE IMPORTED) + set_target_properties(FFTW::Float + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_LIB}" + ) +else() + set(FFTW_FLOAT_LIB_FOUND FALSE) +endif() + +if (FFTW_LONGDOUBLE_LIB) + set(FFTW_LONGDOUBLE_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_LIB}) + add_library(FFTW::LongDouble INTERFACE IMPORTED) + set_target_properties(FFTW::LongDouble + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_LIB}" + ) +else() + set(FFTW_LONGDOUBLE_LIB_FOUND FALSE) +endif() + +if (FFTW_DOUBLE_THREADS_LIB) + set(FFTW_DOUBLE_THREADS_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_THREADS_LIB}) + add_library(FFTW::DoubleThreads INTERFACE IMPORTED) + set_target_properties(FFTW::DoubleThreads + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_THREADS_LIB}" + ) +else() + set(FFTW_DOUBLE_THREADS_LIB_FOUND FALSE) +endif() + +if (FFTW_FLOAT_THREADS_LIB) + set(FFTW_FLOAT_THREADS_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_THREADS_LIB}) + add_library(FFTW::FloatThreads INTERFACE IMPORTED) + set_target_properties(FFTW::FloatThreads + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_THREADS_LIB}" + ) +else() + set(FFTW_FLOAT_THREADS_LIB_FOUND FALSE) +endif() + +if (FFTW_LONGDOUBLE_THREADS_LIB) + set(FFTW_LONGDOUBLE_THREADS_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_THREADS_LIB}) + add_library(FFTW::LongDoubleThreads INTERFACE IMPORTED) + set_target_properties(FFTW::LongDoubleThreads + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_THREADS_LIB}" + ) +else() + set(FFTW_LONGDOUBLE_THREADS_LIB_FOUND FALSE) +endif() + +if (FFTW_DOUBLE_OPENMP_LIB) + set(FFTW_DOUBLE_OPENMP_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_OPENMP_LIB}) + add_library(FFTW::DoubleOpenMP INTERFACE IMPORTED) + set_target_properties(FFTW::DoubleOpenMP + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_OPENMP_LIB}" + ) +else() + set(FFTW_DOUBLE_OPENMP_LIB_FOUND FALSE) +endif() + +if (FFTW_FLOAT_OPENMP_LIB) + set(FFTW_FLOAT_OPENMP_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_OPENMP_LIB}) + add_library(FFTW::FloatOpenMP INTERFACE IMPORTED) + set_target_properties(FFTW::FloatOpenMP + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_OPENMP_LIB}" + ) +else() + set(FFTW_FLOAT_OPENMP_LIB_FOUND FALSE) +endif() + +if (FFTW_LONGDOUBLE_OPENMP_LIB) + set(FFTW_LONGDOUBLE_OPENMP_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_OPENMP_LIB}) + add_library(FFTW::LongDoubleOpenMP INTERFACE IMPORTED) + set_target_properties(FFTW::LongDoubleOpenMP + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_OPENMP_LIB}" + ) +else() + set(FFTW_LONGDOUBLE_OPENMP_LIB_FOUND FALSE) +endif() + +if (FFTW_DOUBLE_MPI_LIB) + set(FFTW_DOUBLE_MPI_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_MPI_LIB}) + add_library(FFTW::DoubleMPI INTERFACE IMPORTED) + set_target_properties(FFTW::DoubleMPI + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_MPI_LIB}" + ) +else() + set(FFTW_DOUBLE_MPI_LIB_FOUND FALSE) +endif() + +if (FFTW_FLOAT_MPI_LIB) + set(FFTW_FLOAT_MPI_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_MPI_LIB}) + add_library(FFTW::FloatMPI INTERFACE IMPORTED) + set_target_properties(FFTW::FloatMPI + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_MPI_LIB}" + ) +else() + set(FFTW_FLOAT_MPI_LIB_FOUND FALSE) +endif() + +if (FFTW_LONGDOUBLE_MPI_LIB) + set(FFTW_LONGDOUBLE_MPI_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_MPI_LIB}) + add_library(FFTW::LongDoubleMPI INTERFACE IMPORTED) + set_target_properties(FFTW::LongDoubleMPI + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_MPI_LIB}" + ) +else() + set(FFTW_LONGDOUBLE_MPI_LIB_FOUND FALSE) +endif() + +#--------------------------------------- end components + +set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV} ) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(FFTW + REQUIRED_VARS FFTW_INCLUDE_DIRS + HANDLE_COMPONENTS + ) + +mark_as_advanced( + FFTW_INCLUDE_DIRS + FFTW_LIBRARIES + FFTW_FLOAT_LIB + FFTW_DOUBLE_LIB + FFTW_LONGDOUBLE_LIB + FFTW_FLOAT_THREADS_LIB + FFTW_DOUBLE_THREADS_LIB + FFTW_LONGDOUBLE_THREADS_LIB + FFTW_FLOAT_OPENMP_LIB + FFTW_DOUBLE_OPENMP_LIB + FFTW_LONGDOUBLE_OPENMP_LIB + FFTW_FLOAT_MPI_LIB + FFTW_DOUBLE_MPI_LIB + FFTW_LONGDOUBLE_MPI_LIB + ) diff --git a/cmake/find_scripts/FindFFTW-eigen.cmake b/cmake/find_scripts/FindFFTW-eigen.cmake new file mode 100644 index 00000000000..e0415e3d944 --- /dev/null +++ b/cmake/find_scripts/FindFFTW-eigen.cmake @@ -0,0 +1,119 @@ +# - Find the FFTW library +# +# Usage: +# find_package(FFTW [REQUIRED] [QUIET] ) +# +# It sets the following variables: +# FFTW_FOUND ... true if fftw is found on the system +# FFTW_LIBRARIES ... full path to fftw library +# FFTW_INCLUDES ... fftw include directory +# +# The following variables will be checked by the function +# FFTW_USE_STATIC_LIBS ... if true, only static libraries are found +# FFTW_ROOT ... if set, the libraries are exclusively searched +# under this path +# FFTW_LIBRARY ... fftw library to use +# FFTW_INCLUDE_DIR ... fftw include directory +# + +#If environment variable FFTWDIR is specified, it has same effect as FFTW_ROOT +if( NOT FFTW_ROOT AND ENV{FFTWDIR} ) + set( FFTW_ROOT $ENV{FFTWDIR} ) +endif() + +# Check if we can use PkgConfig +include(CMakeFindDependencyMacro) +find_dependency(PkgConfig) + +#Determine from PKG +if( PKG_CONFIG_FOUND AND NOT FFTW_ROOT ) + pkg_check_modules( PKG_FFTW QUIET "fftw3" ) +endif() + +#Check whether to search static or dynamic libs +set( CMAKE_FIND_LIBRARY_SUFFIXES_SAV ${CMAKE_FIND_LIBRARY_SUFFIXES} ) + +if( ${FFTW_USE_STATIC_LIBS} ) + set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX} ) +else() + set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX} ) +endif() + +if( FFTW_ROOT ) + + #find libs + find_library( + FFTW_LIB + NAMES "fftw3" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTWF_LIB + NAMES "fftw3f" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTWL_LIB + NAMES "fftw3l" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + #find includes + find_path( + FFTW_INCLUDES + NAMES "fftw3.h" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "include" + NO_DEFAULT_PATH + ) + +else() + + find_library( + FFTW_LIB + NAMES "fftw3" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_library( + FFTWF_LIB + NAMES "fftw3f" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + + find_library( + FFTWL_LIB + NAMES "fftw3l" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} + ) + + find_path( + FFTW_INCLUDES + NAMES "fftw3.h" + PATHS ${PKG_FFTW_INCLUDE_DIRS} ${INCLUDE_INSTALL_DIR} + ) + +endif() + +set(FFTW_LIBRARIES ${FFTW_LIB} ${FFTWF_LIB}) + +if(FFTWL_LIB) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTWL_LIB}) +endif() + +set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV} ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(FFTW DEFAULT_MSG + FFTW_INCLUDES FFTW_LIBRARIES) + +mark_as_advanced(FFTW_INCLUDES FFTW_LIBRARIES FFTW_LIB FFTWF_LIB FFTWL_LIB) diff --git a/cmake/find_scripts/FindFFTW.cmake b/cmake/find_scripts/FindFFTW.cmake new file mode 100644 index 00000000000..f9c92a4c33d --- /dev/null +++ b/cmake/find_scripts/FindFFTW.cmake @@ -0,0 +1,65 @@ +find_path(FFTW_INCLUDE_DIR fftw3.h) + +if(FFTW_INCLUDE_DIR) + set(HAVE_FFTW3_H 1) + message(STATUS "Found fftw3.h in ${FFTW_INCLUDE_DIR}") +else() + find_path(FFTW_INCLUDE_DIR fftw.h) + if(FFTW_INCLUDE_DIR) + set(HAVE_FFTW_H 1) + message(STATUS "Found fftw.h in ${FFTW_INCLUDE_DIR}") + endif() +endif() + +find_path(DFFTW_INCLUDE_DIR dfftw.h) +if(DFFTW_INCLUDE_DIR) + set(HAVE_DFFTW_H 1) + message(STATUS "Found dfftw.h in ${FFTW_INCLUDE_DIR}") +endif() + +# fftw double lib +find_library(FFTWD_LIB fftw3) +find_library(FFTWD_THREADS_LIB fftw3_threads) # threads support + +set(FFTW_LIBRARIES) +if(FFTWD_LIB) + set(FFTWD_FOUND 1) + set(FFTW_LIBRARIES ${FFTWD_LIB}) + if(FFTWD_THREADS_LIB) + set(FFTW_LIBRARIES "${FFTW_LIBRARIES};${FFTWD_THREADS_LIB}") + endif() +endif() + +# Single Precision +find_library(FFTWF_LIB fftw3f) +find_library(FFTWF_THREADS_LIB fftw3f_threads) # threads support + +if(FFTWF_LIB) + set(FFTWF_FOUND 1) + set(FFTW_LIBRARIES "${FFTW_LIBRARIES};${FFTWF_LIB}") + if(FFTWF_THREADS_LIB) + set(FFTW_LIBRARIES "${FFTW_LIBRARIES};${FFTWF_THREADS_LIB}") + endif() +endif() + +if(NOT FFTWD_FOUND AND NOT FFTWF_FOUND) + set(FFTW_FOUND FALSE) +endif() + +mark_as_advanced( + FFTW_LIBRARIES + FFTW_INCLUDE_DIR + DFFTW_INCLUDE_DIR + FFTWF_LIB + FFTWF_THREADS_LIB + FFTWD_LIB + FFTWD_THREADS_LIB) + +# copy HAVE_ to parent scope so that we can use in include/CMakeLists.txt and +# rest +set(HAVE_FFTW3_H ${HAVE_FFTW3_H}) +set(HAVE_FFTW_H ${HAVE_FFTW_H}) +set(HAVE_DFFTW_H ${HAVE_DFFTW_H}) +include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake) +find_package_handle_standard_args(FFTW REQUIRED_VARS FFTW_LIBRARIES + FFTW_INCLUDE_DIR) diff --git a/cmake/find_scripts/FindFontConfig.cmake b/cmake/find_scripts/FindFontConfig.cmake new file mode 100644 index 00000000000..c7d228c7cc2 --- /dev/null +++ b/cmake/find_scripts/FindFontConfig.cmake @@ -0,0 +1,37 @@ +#[[ +- Find FontConfig library +Find the FontConfig includes and library +This module defines + FONTCONFIG_INCLUDE_DIR, where to find fontconfig.h + FONTCONFIG_LIBRARIES, libraries to link against to use the FontConfig API. + FONTCONFIG_FOUND, If false, do not try to use FontConfig. + +============================================================================= +Copyright 2012 Kitware, Inc. + +Distributed under the OSI-approved BSD License (the "License"); +see accompanying file Copyright.txt for details. + +This software is distributed WITHOUT ANY WARRANTY; without even the +implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the License for more information. +============================================================================= +(To distribute this file outside of VTK, substitute the full + License text for the above reference.) +#]] + +find_path(FONTCONFIG_INCLUDE_DIR fontconfig/fontconfig.h) + +find_library(FONTCONFIG_LIBRARY NAMES fontconfig) + +# handle the QUIETLY and REQUIRED arguments and set FONTCONFIG_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(FontConfig DEFAULT_MSG FONTCONFIG_LIBRARY + FONTCONFIG_INCLUDE_DIR) + +if(FONTCONFIG_FOUND) + set(FONTCONFIG_LIBRARIES ${FONTCONFIG_LIBRARY}) +endif() + +mark_as_advanced(FONTCONFIG_INCLUDE_DIR FONTCONFIG_LIBRARY FONTCONFIG_LIBRARIES) diff --git a/cmake/find_scripts/FindGDAL.cmake b/cmake/find_scripts/FindGDAL.cmake new file mode 100644 index 00000000000..08479a2d7dd --- /dev/null +++ b/cmake/find_scripts/FindGDAL.cmake @@ -0,0 +1,25 @@ +find_path(GDAL_INCLUDE_DIR gdal.h PATH_SUFFIXES gdal) + +find_library(GDAL_LIBRARY_RELEASE NAMES gdal_i gdal) +find_library(GDAL_LIBRARY_DEBUG NAMES gdald) +set(GDAL_FOUND FALSE) + +set(GDAL_LIBRARY) +if(GDAL_LIBRARY_DEBUG) + set(GDAL_LIBRARY + ${GDAL_LIBRARY_DEBUG} + CACHE FILEPATH "doc") +elseif(GDAL_LIBRARY_RELEASE) + set(GDAL_LIBRARY + ${GDAL_LIBRARY_RELEASE} + CACHE FILEPATH "doc") +endif() + +mark_as_advanced(GDAL_LIBRARY_RELEASE) +mark_as_advanced(GDAL_LIBRARY_DEBUG) +mark_as_advanced(GDAL_LIBRARY) +mark_as_advanced(GDAL_INCLUDE_DIR) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GDAL DEFAULT_MSG GDAL_LIBRARY + GDAL_INCLUDE_DIR) diff --git a/cmake/find_scripts/FindGEOS.cmake b/cmake/find_scripts/FindGEOS.cmake new file mode 100644 index 00000000000..17fe3831095 --- /dev/null +++ b/cmake/find_scripts/FindGEOS.cmake @@ -0,0 +1,52 @@ +#[[ +File: FindGEOS.cmake + +Find the native GEOS(Geometry Engine - Open Source) includes and libraries. + +This module defines: + +GEOS_INCLUDE_DIR, where to find geos.h, etc. + +GEOS_LIBRARY, libraries to link against to use GEOS. Currently there are +two looked for, geos and geos_c libraries. + +GEOS_FOUND, True if found, false if one of the above are not found. +For ossim, typically geos will be system installed which should be found; +or found in the ossim 3rd party dependencies directory from a geos build +and install. If the latter it will rely on CMAKE_INCLUDE_PATH and +CMAKE_LIBRARY_PATH having the path to the party dependencies directory. + +NOTE: +This script is specialized for ossim, e.g. looking in /usr/local/ossim. + +$Id$ +--- + +--- +Find include path: +Note: Ubuntu 14.04+ did not have geos.h (not included in any ossim src). +Instead looking for Geometry.h +--- +#]] + +find_path(GEOS_INCLUDE_DIR geos_c.h) + +# Find GEOS C library: +find_library(GEOS_C_LIBRARY_RELEASE NAMES geos_c) +find_library(GEOS_C_LIBRARY_DEBUG NAMES geos_cd) +set(GEOS_FOUND FALSE) + +set(GEOS_C_LIBRARY) +if(GEOS_C_LIBRARY_DEBUG) + set(GEOS_C_LIBRARY ${GEOS_C_LIBRARY_DEBUG}) +elseif(GEOS_C_LIBRARY_RELEASE) + set(GEOS_C_LIBRARY ${GEOS_C_LIBRARY_RELEASE}) +endif() + +mark_as_advanced(GEOS_INCLUDE_DIR GEOS_C_LIBRARY GEOS_C_LIBRARY_RELEASE + GEOS_C_LIBRARY_DEBUG) + +# --- This function sets GEOS_FOUND if variables are valid. --- +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GEOS DEFAULT_MSG GEOS_C_LIBRARY + GEOS_INCLUDE_DIR) diff --git a/cmake/find_scripts/FindIconv.cmake b/cmake/find_scripts/FindIconv.cmake new file mode 100644 index 00000000000..fe9089df133 --- /dev/null +++ b/cmake/find_scripts/FindIconv.cmake @@ -0,0 +1,58 @@ +#[[ +- Try to find Iconv +Once done this will define + +ICONV_FOUND - system has Iconv +ICONV_INCLUDE_DIR - the Iconv include directory +ICONV_LIBRARIES - Link these to use Iconv +ICONV_SECOND_ARGUMENT_IS_CONST - the second argument for iconv() is const +#]] + +include(CheckCXXSourceCompiles) + +if(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) + # Already in cache, be silent + set(ICONV_FIND_QUIETLY TRUE) +endif(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) + +find_path(ICONV_INCLUDE_DIR iconv.h) + +find_library(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c) + +if(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) + set(ICONV_FOUND TRUE) +endif(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) + +set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR}) +set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES}) +if(ICONV_FOUND) + check_cxx_source_compiles( + " + #include + int main(){ + iconv_t conv = 0; + const char* in = 0; + size_t ilen = 0; + char* out = 0; + size_t olen = 0; + iconv(conv, &in, &ilen, &out, &olen); + return 0; + } +" + ICONV_SECOND_ARGUMENT_IS_CONST) +endif(ICONV_FOUND) +set(CMAKE_REQUIRED_INCLUDES) +set(CMAKE_REQUIRED_LIBRARIES) + +if(ICONV_FOUND) + if(NOT ICONV_FIND_QUIETLY) + message(STATUS "Found Iconv: ${ICONV_LIBRARIES}") + endif(NOT ICONV_FIND_QUIETLY) +else(ICONV_FOUND) + if(Iconv_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Iconv") + endif(Iconv_FIND_REQUIRED) +endif(ICONV_FOUND) + +mark_as_advanced(ICONV_INCLUDE_DIR ICONV_LIBRARIES + ICONV_SECOND_ARGUMENT_IS_CONST) diff --git a/cmake/find_scripts/FindLibLAS.cmake b/cmake/find_scripts/FindLibLAS.cmake new file mode 100644 index 00000000000..c3c5b07c242 --- /dev/null +++ b/cmake/find_scripts/FindLibLAS.cmake @@ -0,0 +1,40 @@ +find_path( + LibLAS_INCLUDE_DIR + NAMES liblas.h + PATH_SUFFIXES capi + PATH_SUFFIXES liblas/capi + DOC "path to liblas.h") + +find_library( + LibLAS_C_LIBRARY + NAMES liblas_c las_c las + # Help the user find it if we cannot. + DOC "path liblas_c library") + +if(LibLAS_INCLUDE_DIR) + unset(las_version_CONTENTS) + file(READ "${LibLAS_INCLUDE_DIR}/las_version.h" las_version_CONTENTS) + + string(REGEX MATCH "#define +LIBLAS_VERSION_MAJOR +([0-9]+)" _dummy + "${las_version_CONTENTS}") + set(LibLAS_VERSION_MAJOR "${CMAKE_MATCH_1}") + string(REGEX MATCH "#define +LIBLAS_VERSION_MINOR +([0-9])" _dummy + "${las_version_CONTENTS}") + set(LibLAS_VERSION_MINOR "${CMAKE_MATCH_1}") + string(REGEX MATCH "#define +LIBLAS_VERSION_REV +([0-9])" _dummy + "${las_version_CONTENTS}") + set(LIBLAS_VERSION_REV "${CMAKE_MATCH_1}") + + set(LibLAS_VERSION_STRING + "${LibLAS_VERSION_MAJOR}.${LibLAS_VERSION_MINOR}.${LIBLAS_VERSION_REV}") +endif() +# message(FATAL_ERROR "LibLAS_LIBRARY=${LibLAS_LIBRARY}") +if(LibLAS_INCLUDE_DIR AND LibLAS_C_LIBRARY) + set(LibLAS_FOUND TRUE) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + LibLAS + REQUIRED_VARS LibLAS_C_LIBRARY LibLAS_INCLUDE_DIR + VERSION_VAR LibLAS_VERSION_STRING) diff --git a/cmake/find_scripts/FindMySQL.cmake b/cmake/find_scripts/FindMySQL.cmake new file mode 100644 index 00000000000..59f36a07726 --- /dev/null +++ b/cmake/find_scripts/FindMySQL.cmake @@ -0,0 +1,16 @@ +execute_process( + COMMAND mysql_config --cflags + OUTPUT_VARIABLE MySQL_INCLUDE_DIRS + OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process( + COMMAND mysql_config --libs + OUTPUT_VARIABLE MySQL_LIBRARY + OUTPUT_STRIP_TRAILING_WHITESPACE) + +if(MySQL_INCLUDE_DIRS AND MySQL_LIBRARY) + string(REGEX REPLACE "(^| +)-I" " " _dummy ${MySQL_INCLUDE_DIRS}) + string(STRIP ${_dummy} _dummy) + string(REPLACE " " ";" MySQL_INCLUDE_DIRS ${_dummy}) + message(STATUS "Found MySQL: ${MySQL_LIBRARY}") + set(MySQL_FOUND TRUE) +endif() diff --git a/cmake/find_scripts/FindNetCDF.cmake b/cmake/find_scripts/FindNetCDF.cmake new file mode 100644 index 00000000000..8939fb9b5bb --- /dev/null +++ b/cmake/find_scripts/FindNetCDF.cmake @@ -0,0 +1,17 @@ +find_path( + NetCDF_INCLUDE_DIR + NAMES netcdf.h + DOC "path to netcdf.h") + +find_library( + NetCDF_LIBRARY + NAMES netcdf + DOC "path netcdf library") + +if(NetCDF_INCLUDE_DIR AND NetCDF_LIBRARY) + set(NetCDF_FOUND TRUE) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NetCDF REQUIRED_VARS NetCDF_LIBRARY + NetCDF_INCLUDE_DIR) diff --git a/cmake/find_scripts/FindPCRE.cmake b/cmake/find_scripts/FindPCRE.cmake new file mode 100644 index 00000000000..002f7af4a6d --- /dev/null +++ b/cmake/find_scripts/FindPCRE.cmake @@ -0,0 +1,27 @@ +find_path(PCRE_INCLUDE_DIR NAMES pcre.h) + +find_library(PCRE_LIBRARY_RELEASE NAMES pcre) +find_library(PCRE_LIBRARY_DEBUG NAMES pcred) +if(PCRE_LIBRARY_DEBUG) + set(PCRE_LIBRARY ${PCRE_LIBRARY_DEBUG}) +elseif(PCRE_LIBRARY_RELEASE) + set(PCRE_LIBRARY ${PCRE_LIBRARY_RELEASE}) +endif() + +set(PCRE_FOUND FALSE) +if(PCRE_INCLUDE_DIR AND PCRE_LIBRARY) + set(PCRE_FOUND TRUE) +endif() + +if(PCRE_FOUND) + set(PCRE_LIBRARIES ${PCRE_LIBRARY}) + set(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR}) +endif() + +mark_as_advanced(PCRE_LIBRARY) +mark_as_advanced(PCRE_LIBRARY_DEBUG) +mark_as_advanced(PCRE_LIBRARY_RELEASE) +mark_as_advanced(PCRE_INCLUDE_DIR) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(PCRE DEFAULT_MSG PCRE_LIBRARY + PCRE_INCLUDE_DIR) diff --git a/cmake/find_scripts/FindPROJ.cmake b/cmake/find_scripts/FindPROJ.cmake new file mode 100644 index 00000000000..03e5e6716e0 --- /dev/null +++ b/cmake/find_scripts/FindPROJ.cmake @@ -0,0 +1,117 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file COPYING-CMAKE-SCRIPTS or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindPROJ +--------- + +CMake module to search for PROJ(PROJ.4 and PROJ) library + +On success, the macro sets the following variables: +``PROJ_FOUND`` + if the library found + +``PROJ_LIBRARIES`` + full path to the library + +``PROJ_INCLUDE_DIRS`` + where to find the library headers + +``PROJ_VERSION_STRING`` + version string of PROJ + +Copyright (c) 2009 Mateusz Loskot +Copyright (c) 2015 NextGIS +Copyright (c) 2018 Hiroshi Miura + +#]=======================================================================] + +find_path( + PROJ_INCLUDE_DIR proj.h + PATHS ${PROJ_ROOT}/include + DOC "Path to PROJ library include directory") + +set(PROJ_NAMES ${PROJ_NAMES} proj proj_i) +set(PROJ_NAMES_DEBUG ${PROJ_NAMES_DEBUG} projd proj_d) + +if(NOT PROJ_LIBRARY) + find_library(PROJ_LIBRARY_RELEASE NAMES ${PROJ_NAMES}) + find_library(PROJ_LIBRARY_DEBUG NAMES ${PROJ_NAMES_DEBUG}) + include(SelectLibraryConfigurations) + select_library_configurations(PROJ) + mark_as_advanced(PROJ_LIBRARY_RELEASE PROJ_LIBRARY_DEBUG) +endif() + +unset(PROJ_NAMES) +unset(PROJ_NAMES_DEBUG) + +if(PROJ_INCLUDE_DIR) + file(READ "${PROJ_INCLUDE_DIR}/proj.h" PROJ_H_CONTENTS) + string(REGEX REPLACE "^.*PROJ_VERSION_MAJOR +([0-9]+).*$" "\\1" + PROJ_VERSION_MAJOR "${PROJ_H_CONTENTS}") + string(REGEX REPLACE "^.*PROJ_VERSION_MINOR +([0-9]+).*$" "\\1" + PROJ_VERSION_MINOR "${PROJ_H_CONTENTS}") + string(REGEX REPLACE "^.*PROJ_VERSION_PATCH +([0-9]+).*$" "\\1" + PROJ_VERSION_PATCH "${PROJ_H_CONTENTS}") + unset(PROJ_H_CONTENTS) + set(PROJ_VERSION_STRING + "${PROJ_VERSION_MAJOR}.${PROJ_VERSION_MINOR}.${PROJ_VERSION_PATCH}") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + PROJ + REQUIRED_VARS PROJ_LIBRARY PROJ_INCLUDE_DIR + VERSION_VAR PROJ_VERSION_STRING) +mark_as_advanced(PROJ_INCLUDE_DIR PROJ_LIBRARY) + +if(PROJ_FOUND) + set(PROJ_LIBRARIES "${PROJ_LIBRARY}") + set(PROJ_INCLUDE_DIRS "${PROJ_INCLUDE_DIR}") + if(NOT TARGET PROJ::proj) + add_library(PROJ::proj UNKNOWN IMPORTED) + set_target_properties( + PROJ::proj PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${PROJ_INCLUDE_DIR}" + IMPORTED_LINK_INTERFACE_LANGUAGES "C") + if(EXISTS "${PROJ_LIBRARY}") + set_target_properties( + PROJ::proj PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${PROJ_LIBRARY}") + endif() + if(EXISTS "${PROJ_LIBRARY_RELEASE}") + set_property( + TARGET PROJ::proj + APPEND + PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties( + PROJ::proj + PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" + IMPORTED_LOCATION_RELEASE "${PROJ_LIBRARY_RELEASE}") + endif() + if(EXISTS "${PROJ_LIBRARY_DEBUG}") + set_property( + TARGET PROJ::proj + APPEND + PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties( + PROJ::proj PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" + IMPORTED_LOCATION_DEBUG "${PROJ_LIBRARY_DEBUG}") + endif() + endif() +endif() + +# find_path(PROJ_INCLUDE_DIR proj.h PATH_SUFFIXES proj) +# +# find_library(PROJ_LIBRARY_RELEASE NAMES proj_i proj) +# find_library(PROJ_LIBRARY_DEBUG NAMES projd) set(PROJ_FOUND FALSE) +# +# set(PROJ_LIBRARY) if(PROJ_LIBRARY_DEBUG) set( PROJ_LIBRARY +# ${PROJ_LIBRARY_DEBUG} CACHE FILEPATH "doc" ) elseif(PROJ_LIBRARY_RELEASE) set( +# PROJ_LIBRARY ${PROJ_LIBRARY_RELEASE} CACHE FILEPATH "doc" ) endif() +# +# mark_as_advanced(PROJ_LIBRARY_RELEASE) mark_as_advanced(PROJ_LIBRARY_DEBUG) +# mark_as_advanced(PROJ_LIBRARY) mark_as_advanced(PROJ_INCLUDE_DIR) +# +# include(FindPackageHandleStandardArgs) find_package_handle_standard_args( PROJ +# DEFAULT_MSG PROJ_LIBRARY PROJ_INCLUDE_DIR ) +# diff --git a/cmake/find_scripts/FindPostgreSQL.cmake b/cmake/find_scripts/FindPostgreSQL.cmake new file mode 100644 index 00000000000..b2260d7b853 --- /dev/null +++ b/cmake/find_scripts/FindPostgreSQL.cmake @@ -0,0 +1,312 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindPostgreSQL +-------------- + +Find the PostgreSQL installation. + +IMPORTED Targets +^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.14 + +This module defines :prop_tgt:`IMPORTED` target ``PostgreSQL::PostgreSQL`` +if PostgreSQL has been found. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module will set the following variables in your project: + +``PostgreSQL_FOUND`` + True if PostgreSQL is found. +``PostgreSQL_LIBRARIES`` + the PostgreSQL libraries needed for linking +``PostgreSQL_INCLUDE_DIRS`` + the directories of the PostgreSQL headers +``PostgreSQL_LIBRARY_DIRS`` + the link directories for PostgreSQL libraries +``PostgreSQL_VERSION_STRING`` + the version of PostgreSQL found +``PostgreSQL_TYPE_INCLUDE_DIR`` + the directories of the PostgreSQL server headers + +Components +^^^^^^^^^^ + +This module contains additional ``Server`` component, that forcibly checks +for the presence of server headers. Note that ``PostgreSQL_TYPE_INCLUDE_DIR`` +is set regardless of the presence of the ``Server`` component in find_package call. + +#]=======================================================================] + +# ---------------------------------------------------------------------------- +# History: +# This module is derived from the module originally found in the VTK source tree. +# +# ---------------------------------------------------------------------------- +# Note: +# PostgreSQL_ADDITIONAL_VERSIONS is a variable that can be used to set the +# version number of the implementation of PostgreSQL. +# In Windows the default installation of PostgreSQL uses that as part of the path. +# E.g C:\Program Files\PostgreSQL\8.4. +# Currently, the following version numbers are known to this module: +# "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0" +# +# To use this variable just do something like this: +# set(PostgreSQL_ADDITIONAL_VERSIONS "9.2" "8.4.4") +# before calling find_package(PostgreSQL) in your CMakeLists.txt file. +# This will mean that the versions you set here will be found first in the order +# specified before the default ones are searched. +# +# ---------------------------------------------------------------------------- +# You may need to manually set: +# PostgreSQL_INCLUDE_DIR - the path to where the PostgreSQL include files are. +# PostgreSQL_LIBRARY_DIR - The path to where the PostgreSQL library files are. +# If FindPostgreSQL.cmake cannot find the include files or the library files. +# +# ---------------------------------------------------------------------------- +# The following variables are set if PostgreSQL is found: +# PostgreSQL_FOUND - Set to true when PostgreSQL is found. +# PostgreSQL_INCLUDE_DIRS - Include directories for PostgreSQL +# PostgreSQL_LIBRARY_DIRS - Link directories for PostgreSQL libraries +# PostgreSQL_LIBRARIES - The PostgreSQL libraries. +# +# The ``PostgreSQL::PostgreSQL`` imported target is also created. +# +# ---------------------------------------------------------------------------- +# If you have installed PostgreSQL in a non-standard location. +# (Please note that in the following comments, it is assumed that +# points to the root directory of the include directory of PostgreSQL.) +# Then you have three options. +# 1) After CMake runs, set PostgreSQL_INCLUDE_DIR to /include and +# PostgreSQL_LIBRARY_DIR to wherever the library pq (or libpq in windows) is +# 2) Use CMAKE_INCLUDE_PATH to set a path to /PostgreSQL<-version>. This will allow find_path() +# to locate PostgreSQL_INCLUDE_DIR by utilizing the PATH_SUFFIXES option. e.g. In your CMakeLists.txt file +# set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "/include") +# 3) Set an environment variable called ${PostgreSQL_ROOT} that points to the root of where you have +# installed PostgreSQL, e.g. . +# +# ---------------------------------------------------------------------------- + +cmake_policy(PUSH) +cmake_policy(SET CMP0057 NEW) # if IN_LIST + +set(PostgreSQL_INCLUDE_PATH_DESCRIPTION "top-level directory containing the PostgreSQL include directories. E.g /usr/local/include/PostgreSQL/8.4 or C:/Program Files/PostgreSQL/8.4/include") +set(PostgreSQL_INCLUDE_DIR_MESSAGE "Set the PostgreSQL_INCLUDE_DIR cmake cache entry to the ${PostgreSQL_INCLUDE_PATH_DESCRIPTION}") +set(PostgreSQL_LIBRARY_PATH_DESCRIPTION "top-level directory containing the PostgreSQL libraries.") +set(PostgreSQL_LIBRARY_DIR_MESSAGE "Set the PostgreSQL_LIBRARY_DIR cmake cache entry to the ${PostgreSQL_LIBRARY_PATH_DESCRIPTION}") +set(PostgreSQL_ROOT_DIR_MESSAGE "Set the PostgreSQL_ROOT system variable to where PostgreSQL is found on the machine E.g C:/Program Files/PostgreSQL/8.4") + + +set(PostgreSQL_KNOWN_VERSIONS ${PostgreSQL_ADDITIONAL_VERSIONS} + "16" "15" "14" "13" "12" "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0") + +# Define additional search paths for root directories. +set( PostgreSQL_ROOT_DIRECTORIES + ENV PostgreSQL_ROOT + ${PostgreSQL_ROOT} +) +foreach(suffix ${PostgreSQL_KNOWN_VERSIONS}) + if(WIN32) + list(APPEND PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES + "PostgreSQL/${suffix}/lib") + list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES + "PostgreSQL/${suffix}/include") + list(APPEND PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES + "PostgreSQL/${suffix}/include/server") + endif() + if(UNIX) + list(APPEND PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES + "postgresql${suffix}" + "pgsql-${suffix}/lib") + list(APPEND PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES + "postgresql${suffix}" + "postgresql/${suffix}" + "pgsql-${suffix}/include") + list(APPEND PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES + "postgresql${suffix}/server" + "postgresql/${suffix}/server" + "pgsql-${suffix}/include/server") + endif() +endforeach() + +# +# Look for an installation. +# +find_path(PostgreSQL_INCLUDE_DIR + NAMES libpq-fe.h + PATHS + # Look in other places. + ${PostgreSQL_ROOT_DIRECTORIES} + PATH_SUFFIXES + pgsql + postgresql + include + ${PostgreSQL_INCLUDE_ADDITIONAL_SEARCH_SUFFIXES} + # Help the user find it if we cannot. + DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}" +) + +find_path(PostgreSQL_TYPE_INCLUDE_DIR + NAMES catalog/pg_type.h + PATHS + # Look in other places. + ${PostgreSQL_ROOT_DIRECTORIES} + PATH_SUFFIXES + postgresql + pgsql/server + postgresql/server + include/server + ${PostgreSQL_TYPE_ADDITIONAL_SEARCH_SUFFIXES} + # Help the user find it if we cannot. + DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}" +) + +# The PostgreSQL library. +set (PostgreSQL_LIBRARY_TO_FIND pq) +# Setting some more prefixes for the library +set (PostgreSQL_LIB_PREFIX "") +if ( WIN32 ) + set (PostgreSQL_LIB_PREFIX ${PostgreSQL_LIB_PREFIX} "lib") + set (PostgreSQL_LIBRARY_TO_FIND ${PostgreSQL_LIB_PREFIX}${PostgreSQL_LIBRARY_TO_FIND}) +endif() + +function(__postgresql_find_library _name) + find_library(${_name} + NAMES ${ARGN} + PATHS + ${PostgreSQL_ROOT_DIRECTORIES} + PATH_SUFFIXES + lib + ${PostgreSQL_LIBRARY_ADDITIONAL_SEARCH_SUFFIXES} + # Help the user find it if we cannot. + DOC "The ${PostgreSQL_LIBRARY_DIR_MESSAGE}" + ) +endfunction() + +# For compatibility with versions prior to this multi-config search, honor +# any PostgreSQL_LIBRARY that is already specified and skip the search. +if(PostgreSQL_LIBRARY) + set(PostgreSQL_LIBRARIES "${PostgreSQL_LIBRARY}") + get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY}" PATH) +else() + __postgresql_find_library(PostgreSQL_LIBRARY_RELEASE ${PostgreSQL_LIBRARY_TO_FIND}) + __postgresql_find_library(PostgreSQL_LIBRARY_DEBUG ${PostgreSQL_LIBRARY_TO_FIND}d) + include(SelectLibraryConfigurations) + select_library_configurations(PostgreSQL) + mark_as_advanced(PostgreSQL_LIBRARY_RELEASE PostgreSQL_LIBRARY_DEBUG) + if(PostgreSQL_LIBRARY_RELEASE) + get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY_RELEASE}" PATH) + elseif(PostgreSQL_LIBRARY_DEBUG) + get_filename_component(PostgreSQL_LIBRARY_DIR "${PostgreSQL_LIBRARY_DEBUG}" PATH) + else() + set(PostgreSQL_LIBRARY_DIR "") + endif() +endif() + +if (PostgreSQL_INCLUDE_DIR) + # Some platforms include multiple pg_config.hs for multi-lib configurations + # This is a temporary workaround. A better solution would be to compile + # a dummy c file and extract the value of the symbol. + file(GLOB _PG_CONFIG_HEADERS "${PostgreSQL_INCLUDE_DIR}/pg_config*.h") + foreach(_PG_CONFIG_HEADER ${_PG_CONFIG_HEADERS}) + if(EXISTS "${_PG_CONFIG_HEADER}") + file(STRINGS "${_PG_CONFIG_HEADER}" pgsql_version_str + REGEX "^#define[\t ]+PG_VERSION_NUM[\t ]+.*") + if(pgsql_version_str) + string(REGEX REPLACE "^#define[\t ]+PG_VERSION_NUM[\t ]+([0-9]*).*" + "\\1" _PostgreSQL_VERSION_NUM "${pgsql_version_str}") + break() + endif() + endif() + endforeach() + if (_PostgreSQL_VERSION_NUM) + # 9.x and older encoding + if (_PostgreSQL_VERSION_NUM LESS 100000) + math(EXPR _PostgreSQL_major_version "${_PostgreSQL_VERSION_NUM} / 10000") + math(EXPR _PostgreSQL_minor_version "${_PostgreSQL_VERSION_NUM} % 10000 / 100") + math(EXPR _PostgreSQL_patch_version "${_PostgreSQL_VERSION_NUM} % 100") + set(PostgreSQL_VERSION_STRING "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}.${_PostgreSQL_patch_version}") + unset(_PostgreSQL_major_version) + unset(_PostgreSQL_minor_version) + unset(_PostgreSQL_patch_version) + else () + math(EXPR _PostgreSQL_major_version "${_PostgreSQL_VERSION_NUM} / 10000") + math(EXPR _PostgreSQL_minor_version "${_PostgreSQL_VERSION_NUM} % 10000") + set(PostgreSQL_VERSION_STRING "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}") + unset(_PostgreSQL_major_version) + unset(_PostgreSQL_minor_version) + endif () + else () + foreach(_PG_CONFIG_HEADER ${_PG_CONFIG_HEADERS}) + if(EXISTS "${_PG_CONFIG_HEADER}") + file(STRINGS "${_PG_CONFIG_HEADER}" pgsql_version_str + REGEX "^#define[\t ]+PG_VERSION[\t ]+\".*\"") + if(pgsql_version_str) + string(REGEX REPLACE "^#define[\t ]+PG_VERSION[\t ]+\"([^\"]*)\".*" + "\\1" PostgreSQL_VERSION_STRING "${pgsql_version_str}") + break() + endif() + endif() + endforeach() + endif () + unset(_PostgreSQL_VERSION_NUM) + unset(pgsql_version_str) +endif() + +if("Server" IN_LIST PostgreSQL_FIND_COMPONENTS) + set(PostgreSQL_Server_FOUND TRUE) + if(NOT PostgreSQL_TYPE_INCLUDE_DIR) + set(PostgreSQL_Server_FOUND FALSE) + endif() +endif() + +# Did we find anything? +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(PostgreSQL + REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR + HANDLE_COMPONENTS + VERSION_VAR PostgreSQL_VERSION_STRING) +set(PostgreSQL_FOUND ${POSTGRESQL_FOUND}) + +function(__postgresql_import_library _target _var _config) + if(_config) + set(_config_suffix "_${_config}") + else() + set(_config_suffix "") + endif() + + set(_lib "${${_var}${_config_suffix}}") + if(EXISTS "${_lib}") + if(_config) + set_property(TARGET ${_target} APPEND PROPERTY + IMPORTED_CONFIGURATIONS ${_config}) + endif() + set_target_properties(${_target} PROPERTIES + IMPORTED_LOCATION${_config_suffix} "${_lib}") + endif() +endfunction() + +# Now try to get the include and library path. +if(PostgreSQL_FOUND) + set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR}) + if(PostgreSQL_TYPE_INCLUDE_DIR) + list(APPEND PostgreSQL_INCLUDE_DIRS ${PostgreSQL_TYPE_INCLUDE_DIR}) + endif() + set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR}) + if (NOT TARGET PostgreSQL::PostgreSQL) + add_library(PostgreSQL::PostgreSQL UNKNOWN IMPORTED) + set_target_properties(PostgreSQL::PostgreSQL PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${PostgreSQL_INCLUDE_DIRS}") + __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "") + __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "RELEASE") + __postgresql_import_library(PostgreSQL::PostgreSQL PostgreSQL_LIBRARY "DEBUG") + endif () +endif() + +mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR) + +cmake_policy(POP) diff --git a/cmake/find_scripts/FindReadline.cmake b/cmake/find_scripts/FindReadline.cmake new file mode 100644 index 00000000000..14981ddf9c2 --- /dev/null +++ b/cmake/find_scripts/FindReadline.cmake @@ -0,0 +1,40 @@ +find_package(PkgConfig) +if(PKG_CONFIG_FOUND) + pkg_check_modules(Readline QUIET "readline") + pkg_check_modules(History QUIET "history") + set(Readline_LIBRARIES ${Readline_LINK_LIBRARIES}) + set(History_LIBRARIES ${History_LINK_LIBRARIES}) +else() + find_path(Readline_ROOT_DIR NAMES include/readline/readline.h) + find_path( + Readline_INCLUDE_DIRS + NAMES readline/readline.h + HINTS ${Readline_ROOT_DIR}/include) + find_library( + Readline_LIBRARIES + NAMES readline + HINTS ${Readline_ROOT_DIR}/lib) + if(Readline_INCLUDE_DIRS AND Readline_LIBRARIES) + set(Readline_FOUND TRUE) + endif() + + find_path( + History_INCLUDE_DIRS + NAMES readline/readline.h + HINTS ${Readline_ROOT_DIR}/include) + find_library( + History_LIBRARIES + NAMES readline + HINTS ${Readline_ROOT_DIR}/lib) + if(History_INCLUDE_DIRS AND History_LIBRARIES) + set(History_FOUND TRUE) + endif() +endif() + +if(Readline_FOUND) + message(STATUS "Found Readline: ${Readline_LIBRARIES}") +endif() + +if(History_FOUND) + message(STATUS "Found History: ${History_LIBRARIES}") +endif() diff --git a/cmake/find_scripts/FindSQLite.cmake b/cmake/find_scripts/FindSQLite.cmake new file mode 100644 index 00000000000..19da96bf203 --- /dev/null +++ b/cmake/find_scripts/FindSQLite.cmake @@ -0,0 +1,9 @@ +find_path(SQLITE_INCLUDE_DIR sqlite3.h) +find_library(SQLITE_LIBRARY NAMES sqlite3) + +mark_as_advanced(SQLITE_LIBRARY) +mark_as_advanced(SQLITE_INCLUDE_DIR) + +include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake) +find_package_handle_standard_args(SQLite REQUIRED_VARS SQLITE_LIBRARY + SQLITE_INCLUDE_DIR) diff --git a/cmake/find_scripts/Findzstd.cmake b/cmake/find_scripts/Findzstd.cmake new file mode 100644 index 00000000000..2b2d4428a66 --- /dev/null +++ b/cmake/find_scripts/Findzstd.cmake @@ -0,0 +1,22 @@ +find_package(PkgConfig) +if(PKG_CONFIG_FOUND) + pkg_check_modules(zstd QUIET "libzstd") + set(zstd_LIBRARIES ${zstd_LINK_LIBRARIES}) +else() + find_path(zstd_ROOT_DIR NAMES include/zstd.h) + find_path( + zstd_INCLUDE_DIRS + NAMES zstd.h + HINTS ${zstd_ROOT_DIR}/include) + find_library( + zstd_LIBRARIES + NAMES zstd + HINTS ${zstd_ROOT_DIR}/lib) + if(zstd_INCLUDE_DIRS AND zstd_LIBRARIES) + set(zstd_FOUND TRUE) + endif() +endif() + +if(zstd_FOUND) + message(STATUS "Found zstd: ${zstd_LIBRARIES}") +endif() diff --git a/cmake/locale_strings.cmake b/cmake/locale_strings.cmake new file mode 100644 index 00000000000..3c31db02053 --- /dev/null +++ b/cmake/locale_strings.cmake @@ -0,0 +1,87 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: create translation strings for grass scripts + environment. TODO use custom_command POST_BUILD directly +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +-DBINARY_DIR= +-DG_NAME= +-DSRC_SCRIPT_FILE= +-DOUTPUT_FILE= +-DSOURCE_DIR= +#]] + +set(GISBASE ${BINARY_DIR}/gisbase) +file(TO_NATIVE_PATH "${SOURCE_DIR}" MODULE_TOPDIR) +file(TO_NATIVE_PATH "${GISBASE}" GISBASE_NATIVE) +file(TO_NATIVE_PATH "${GISBASE}/bin" BIN_DIR) +file(TO_NATIVE_PATH "${GISBASE}/lib" LIB_DIR) +file(TO_NATIVE_PATH "${GISBASE}/scripts" SCRIPTS_DIR) +file(TO_NATIVE_PATH "${GISBASE}/etc/config/rc" GISRC) +file(TO_NATIVE_PATH "${GISBASE}/etc/python" ETC_PYTHON_DIR) +file(TO_NATIVE_PATH "${GISBASE}/gui/wxpython" GUI_WXPYTHON_DIR) + +if(WIN32) + set(sep "\;") + set(env_path "") +else() + set(sep ":") + set(env_path ":$ENV{PATH}") +endif() + +set(ENV{GISBASE} "${GISBASE_NATIVE}") +set(ENV{GISRC} ${GISRC}) +set(ENV{PATH} "${BIN_DIR}${sep}${SCRIPTS_DIR}${env_path}") +set(ENV{PYTHONPATH} + "${ETC_PYTHON_DIR}${sep}${GUI_WXPYTHON_DIR}${sep}$ENV{PYTHONPATH}") +if(NOT MSVC) + set(ENV{LD_LIBRARY_PATH} "${LIB_DIR}${sep}$ENV{LD_LIBRARY_PATH}") +endif() +set(ENV{LC_ALL} C) +set(ENV{LANG} C) +set(ENV{LANGUAGE} C) +set(ENV{MODULE_TOPDIR} ${MODULE_TOPDIR}) + +set(SCRIPT_EXT "") +if(WIN32) + set(SCRIPT_EXT ".py") +endif() + +if(WIN32) + set(PGM_NAME ${G_NAME}) + configure_file(${SOURCE_DIR}/cmake/windows_launch.bat.in + ${GISBASE}/scripts/${G_NAME}.bat @ONLY) +endif(WIN32) + +set(TMP_SCRIPT_FILE ${BINARY_DIR}/CMakeFiles/${G_NAME}${SCRIPT_EXT}) +configure_file(${SRC_SCRIPT_FILE} ${TMP_SCRIPT_FILE} COPYONLY) +file( + COPY ${TMP_SCRIPT_FILE} + DESTINATION ${GISBASE}/scripts/ + FILE_PERMISSIONS + OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE) + +execute_process( + COMMAND ${BIN_DIR}/bin/g.parser -t ${GISBASE}/scripts/${G_NAME}${SCRIPT_EXT} + OUTPUT_VARIABLE run_g_parser_OV + ERROR_VARIABLE run_g_parser_EV + RESULT_VARIABLE run_g_parser_RV) + +string(REGEX REPLACE "\n" ";" varname "${run_g_parser_OV}") +set(output_to_write) +foreach(line ${varname}) + string(REPLACE "\"" "\\\"" line "${line}") + set(line "_(\"${line}\")") + list(APPEND output_to_write "${line}") +endforeach() + +string(REGEX REPLACE ";" "\n" output_to_write "${output_to_write}") +file(WRITE "${OUTPUT_FILE}" "${output_to_write}\n") +file(REMOVE ${TMP_SCRIPT_FILE}) diff --git a/cmake/modules/CheckDependentLibraries.cmake b/cmake/modules/CheckDependentLibraries.cmake new file mode 100644 index 00000000000..9d234af783b --- /dev/null +++ b/cmake/modules/CheckDependentLibraries.cmake @@ -0,0 +1,433 @@ +#[=======================================================================[.rst: +CheckDependentLibraries.cmake +----------------------------- + +Detect GRASS dependencies and set variable HAVE_* + +#]=======================================================================] + +# Required dependencies + +find_package(FLEX REQUIRED) + +find_package(BISON REQUIRED) + +if(UNIX) + find_library(M_LIBRARY m) + add_library(LIBM INTERFACE IMPORTED GLOBAL) + set_property(TARGET LIBM PROPERTY INTERFACE_LINK_LIBRARIES ${M_LIBRARY}) + mark_as_advanced(M_LIBRARY) +endif() + +find_package(PROJ REQUIRED) +if(PROJ_FOUND) + add_library(PROJ INTERFACE IMPORTED GLOBAL) + set_property(TARGET PROJ PROPERTY INTERFACE_LINK_LIBRARIES + ${PROJ_LIBRARY${find_library_suffix}}) + set_property(TARGET PROJ PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${PROJ_INCLUDE_DIR}) +endif() + +find_package(GDAL REQUIRED) +if(GDAL_FOUND) + add_library(GDAL INTERFACE IMPORTED GLOBAL) + set_property(TARGET GDAL PROPERTY INTERFACE_LINK_LIBRARIES ${GDAL_LIBRARY}) + set_property(TARGET GDAL PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${GDAL_INCLUDE_DIR}) +endif() + +find_package(ZLIB REQUIRED) +if(ZLIB_FOUND) + add_library(ZLIB INTERFACE IMPORTED GLOBAL) + set_property(TARGET ZLIB PROPERTY INTERFACE_LINK_LIBRARIES + ${ZLIB_LIBRARY${find_library_suffix}}) + set_property(TARGET ZLIB PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${ZLIB_INCLUDE_DIR}) +endif() + +# Optional dependencies + +if(MSVC) + find_package(PCRE REQUIRED) + if(PCRE_FOUND) + add_library(PCRE INTERFACE IMPORTED GLOBAL) + set_property(TARGET PCRE PROPERTY INTERFACE_LINK_LIBRARIES + ${PCRE_LIBRARY${find_library_suffix}}) + set_property(TARGET PCRE PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${PCRE_INCLUDE_DIR}) + endif() +endif() + +find_package(Iconv QUIET) +if(ICONV_FOUND) + add_library(ICONV INTERFACE IMPORTED GLOBAL) + set_property(TARGET ICONV PROPERTY INTERFACE_LINK_LIBRARIES + ${ICONV_LIBRARIES}) + set_property(TARGET ICONV PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${ICONV_INCLUDE_DIR}) + # if(ICONV_SECOND_ARGUMENT_IS_CONST) set() update this value in + # include/config.cmake.in +endif() + +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads) +if(Threads_FOUND) + add_library(PTHREAD INTERFACE IMPORTED GLOBAL) + if(THREADS_HAVE_PTHREAD_ARG) + set_property(TARGET PTHREAD PROPERTY INTERFACE_COMPILE_OPTIONS "-pthread") + endif() + if(CMAKE_THREAD_LIBS_INIT) + set_property(TARGET PTHREAD PROPERTY INTERFACE_LINK_LIBRARIES + "${CMAKE_THREAD_LIBS_INIT}") + endif() +endif() + +# Graphics options + +if(WITH_X11) + find_package(X11 REQUIRED) + if(X11_FOUND) + add_library(X11 INTERFACE IMPORTED GLOBAL) + set_property(TARGET X11 PROPERTY INTERFACE_LINK_LIBRARIES ${X11_LIBRARIES}) + set_property(TARGET X11 PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${X11_INCLUDE_DIR}) + endif() +endif() + +if(WITH_OPENGL) + find_package(OpenGL REQUIRED) + if(OPENGL_FOUND) + add_library(OPENGL INTERFACE IMPORTED GLOBAL) + if(APPLE) + find_library(AGL_FRAMEWORK AGL DOC "AGL lib for OSX") + set(APP "-framework AGL -framework ApplicationServices") + endif() + set_property(TARGET OPENGL PROPERTY INTERFACE_LINK_LIBRARIES + ${OPENGL_LIBRARIES} ${AGL_FRAMEWORK}) + set_property(TARGET OPENGL PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${OPENGL_INCLUDE_DIR} ${AGL_FRAMEWORK}) + endif() +endif() + +if(WITH_CAIRO) + find_package(Cairo REQUIRED) + if(CAIRO_FOUND) + add_library(CAIRO INTERFACE IMPORTED GLOBAL) + set_property(TARGET CAIRO PROPERTY INTERFACE_LINK_LIBRARIES + ${CAIRO_LIBRARIES}) + set_property(TARGET CAIRO PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${CAIRO_INCLUDE_DIRS}) + endif() +endif() + +if(WITH_LIBPNG) + find_package(PNG REQUIRED) + if(PNG_FOUND) + add_library(LIBPNG INTERFACE IMPORTED GLOBAL) + set_property(TARGET LIBPNG PROPERTY INTERFACE_LINK_LIBRARIES + ${PNG_LIBRARY${find_library_suffix}}) + set_property(TARGET LIBPNG PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${PNG_INCLUDE_DIR}) + endif() +endif() + +# Data storage options + +if(WITH_SQLITE) + find_package(SQLite REQUIRED) + if(SQLITE_FOUND) + add_library(SQLITE INTERFACE IMPORTED GLOBAL) + set_property(TARGET SQLITE PROPERTY INTERFACE_LINK_LIBRARIES + ${SQLITE_LIBRARY}) + set_property(TARGET SQLITE PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${SQLITE_INCLUDE_DIRS}) + endif() +endif() + +if(WITH_POSTGRES) + find_package(PostgreSQL REQUIRED) + if(PostgreSQL_FOUND) + add_library(POSTGRES INTERFACE IMPORTED GLOBAL) + set_property(TARGET POSTGRES PROPERTY INTERFACE_LINK_LIBRARIES + ${PostgreSQL_LIBRARY}) + set_property(TARGET POSTGRES PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${PostgreSQL_INCLUDE_DIR}) + endif() +endif() + +if(WITH_MYSQL) + find_package(MySQL REQUIRED) + if(MySQL_FOUND) + add_library(MYSQL INTERFACE IMPORTED GLOBAL) + set_property(TARGET MYSQL PROPERTY INTERFACE_LINK_LIBRARIES + ${MySQL_LIBRARY}) + set_property(TARGET MYSQL PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${MySQL_INCLUDE_DIRS}) + endif() +endif() + +if(WITH_ODBC AND WIN32) + find_package(ODBC QUIET) + if(ODBC_FOUND) + add_library(ODBC INTERFACE IMPORTED GLOBAL) + #[[ + set_property(TARGET ODBC PROPERTY INTERFACE_LINK_LIBRARIES ${ODBC_LIBRARIES}) + set_property(TARGET PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${ODBC_INCLUDE_DIRS}) + #]] + endif() +endif() + +if(WITH_ZSTD) + find_package(zstd REQUIRED) + if(zstd_FOUND) + add_library(ZSTD INTERFACE IMPORTED GLOBAL) + set_property(TARGET ZSTD PROPERTY INTERFACE_LINK_LIBRARIES + ${zstd_LIBRARIES}) + set_property(TARGET ZSTD PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${zstd_INCLUDE_DIRS}) + endif() +endif() + +if(WITH_BZLIB) + find_package(BZip2 REQUIRED) + if(BZIP2_FOUND) + add_library(BZIP2 INTERFACE IMPORTED GLOBAL) + set_property(TARGET BZIP2 PROPERTY INTERFACE_LINK_LIBRARIES + ${BZIP2_LIBRARY${find_library_suffix}}) + set_property(TARGET BZIP2 PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${BZIP2_INCLUDE_DIR}) + endif() +endif() + +# Command-line options +if(WITH_READLINE) + find_package(Readline REQUIRED) + if(Readline_FOUND) + add_library(READLINE INTERFACE IMPORTED GLOBAL) + set_property(TARGET READLINE PROPERTY INTERFACE_LINK_LIBRARIES + ${Readline_LIBRARIES}) + set_property(TARGET READLINE PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${Readline_INCLUDE_DIRS}) + endif() + if(History_FOUND) + add_library(HISTORY INTERFACE IMPORTED GLOBAL) + set_property(TARGET HISTORY PROPERTY INTERFACE_LINK_LIBRARIES + ${History_LIBRARIES}) + set_property(TARGET HISTORY PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${History_INCLUDE_DIRS}) + endif() +endif() + +# Language options +if(WITH_FREETYPE) + find_package(Freetype REQUIRED) + if(FREETYPE_FOUND) + add_library(FREETYPE INTERFACE IMPORTED GLOBAL) + set_property( + TARGET FREETYPE PROPERTY INTERFACE_LINK_LIBRARIES + ${FREETYPE_LIBRARY${find_library_suffix}}) + set_property(TARGET FREETYPE PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${FREETYPE_INCLUDE_DIRS}) + endif() +endif() + +# Computing options +if(WITH_FFTW) + find_package(FFTW REQUIRED) + if(FFTW_FOUND) + add_library(FFTW INTERFACE IMPORTED GLOBAL) + set_property(TARGET FFTW PROPERTY INTERFACE_LINK_LIBRARIES + ${FFTW_LIBRARIES}) + set_property(TARGET FFTW PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${FFTW_INCLUDE_DIR}) + endif() +endif() + +if(WITH_BLAS) + find_package(BLAS REQUIRED) + if(BLAS_FOUND) + add_library(BLAS INTERFACE IMPORTED GLOBAL) + set_property(TARGET BLAS PROPERTY INTERFACE_LINK_LIBRARIES + ${BLAS_LIBRARIES}) + endif() +endif() + +if(WITH_LAPACK) + find_package(LAPACK REQUIRED) + if(LAPACK_FOUND) + add_library(LAPACK INTERFACE IMPORTED GLOBAL) + set_property(TARGET LAPACK PROPERTY INTERFACE_LINK_LIBRARIES + ${LAPACK_LIBRARIES}) + endif() +endif() + +if(WITH_OPENMP) + find_package(OpenMP REQUIRED) +endif() + +# Data format options +if(WITH_TIFF) + find_package(TIFF REQUIRED) + if(TIFF_FOUND) + add_library(TIFF INTERFACE IMPORTED GLOBAL) + set_property(TARGET TIFF PROPERTY INTERFACE_LINK_LIBRARIES + ${TIFF_LIBRARY${find_library_suffix}}) + set_property(TARGET TIFF PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${TIFF_INCLUDE_DIR}) + endif() +endif() + +if(WITH_NETCDF) + find_package(NetCDF REQUIRED) + if(NetCDF_FOUND) + add_library(NETCDF INTERFACE IMPORTED GLOBAL) + set_property(TARGET NETCDF PROPERTY INTERFACE_LINK_LIBRARIES + ${NetCDF_LIBRARY}) + set_property(TARGET NETCDF PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${NetCDF_INCLUDE_DIR}) + endif() +endif() + +if(WITH_GEOS) + find_package(GEOS REQUIRED) + if(GEOS_FOUND) + add_library(GEOS INTERFACE IMPORTED GLOBAL) + set_property(TARGET GEOS PROPERTY INTERFACE_LINK_LIBRARIES + ${GEOS_C_LIBRARY${find_library_suffix}}) + set_property(TARGET GEOS PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${GEOS_INCLUDE_DIR}) + endif() +endif() + +if(WITH_PDAL) + find_package(PDAL REQUIRED) + if(PDAL_FOUND) + add_library(PDAL INTERFACE IMPORTED GLOBAL) + set_property(TARGET PDAL PROPERTY INTERFACE_LINK_LIBRARIES + ${PDAL_LIBRARIES}) + set_property(TARGET PDAL PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${PDAL_INCLUDE_DIRS}) + endif() +endif() + +if(WITH_LIBLAS) + find_package(LibLAS REQUIRED) + if(LibLAS_FOUND) + add_library(LIBLAS INTERFACE IMPORTED GLOBAL) + set_property(TARGET LIBLAS PROPERTY INTERFACE_LINK_LIBRARIES + ${LibLAS_C_LIBRARY}) + set_property(TARGET LIBLAS PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ${LibLAS_INCLUDE_DIR}) + endif() +endif() + +find_package(Python3 REQUIRED) +if(Python3_FOUND) + set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) + #[[ + find_package(PythonLibs REQUIRED) + find_package(Numpy) + #]] +endif() + +check_target(PROJ HAVE_PROJ_H) +check_target(GDAL HAVE_GDAL) +check_target(GDAL HAVE_OGR) +check_target(ZLIB HAVE_ZLIB_H) +check_target(ICONV HAVE_ICONV_H) +check_target(LIBPNG HAVE_PNG_H) +check_target(LIBJPEG HAVE_JPEGLIB_H) +check_target(SQLITE HAVE_SQLITE) +check_target(POSTGRES HAVE_POSTGRES) +check_target(MYSQL HAVE_MYSQL_H) +check_target(ODBC HAVE_SQL_H) +check_target(ZSTD HAVE_ZSTD_H) +check_target(BZIP2 HAVE_BZLIB_H) +check_target(READLINE HAVE_READLINE_READLINE_H) +check_target(HISTORY HAVE_READLINE_HISTORY_H) +check_target(FREETYPE HAVE_FT2BUILD_H) +# set(CMAKE_REQUIRED_INCLUDES "${FFTW_INCLUDE_DIR}") no target ATLAS in +# thirdpary/CMakeLists.txt +check_target(ATLAS HAVE_LIBATLAS) +check_target(BLAS HAVE_LIBBLAS) +check_target(BLAS HAVE_CBLAS_H) +check_target(LAPACK HAVE_LIBLAPACK) +check_target(LAPACK HAVE_CLAPACK_H) +check_target(TIFF HAVE_TIFFIO_H) +check_target(NETCDF HAVE_NETCDF) +check_target(GEOS HAVE_GEOS) + +if(TARGET POSTGRES) + try_compile( + HAVE_PQCMDTUPLES ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/cmake/tests/have_pqcmdtuples.c + CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:PATH=${PostgreSQL_INCLUDE_DIR}" "-w" + "-DLINK_LIBRARIES:STRING=${PostgreSQL_LIBRARY}" + OUTPUT_VARIABLE COMPILE_HAVE_PQCMDTUPLES) + if(NOT COMPILE_HAVE_PQCMDTUPLES) + message( + "Performing Test HAVE_PQCMDTUPLES - Failed\n COMPILE_OUTPUT:${COMPILE_HAVE_PQCMDTUPLES}\n" + ) + else() + message(STATUS "Performing Test HAVE_PQCMDTUPLES - Success") + set(HAVE_PQCMDTUPLES 1) + endif() +endif() + +if(MSVC) + check_target(PCRE HAVE_PCRE_H) +endif() + +check_target(POSTGRES HAVE_LIBPQ_FE_H) + +set(HAVE_PBUFFERS 0) +set(HAVE_PIXMAPS 0) +if(WITH_OPENGL) + try_compile( + HAVE_PBUFFERS ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/cmake/tests/have_pbuffer.c + CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:PATH=${OPENGL_INCLUDE_DIR}" "-w" + "-DLINK_LIBRARIES:STRING=${OPENGL_LIBRARIES}" + OUTPUT_VARIABLE COMPILE_HAVE_PBUFFERS) + if(NOT COMPILE_HAVE_PBUFFERS) + message( + FATAL_ERROR + "Performing Test HAVE_PBUFFERS - Failed\n COMPILE_OUTPUT:${COMPILE_HAVE_PBUFFERS}\n" + ) + else() + message(STATUS "Performing Test HAVE_PBUFFERS - Success") + set(HAVE_PBUFFERS 1) + endif() + + try_compile( + HAVE_PIXMAPS ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/cmake/tests/have_pixmaps.c + CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:PATH=${OPENGL_INCLUDE_DIR}" "-w" + "-DLINK_LIBRARIES:STRING=${OPENGL_LIBRARIES}" + OUTPUT_VARIABLE COMPILE_HAVE_PIXMAPS) + + if(NOT COMPILE_HAVE_PIXMAPS) + message( + FATAL_ERROR + "Performing Test HAVE_PIXMAPS - Failed\n COMPILE_OUTPUT:${COMPILE_HAVE_PIXMAPS}\n" + ) + else() + message(STATUS "Performing Test HAVE_PIXMAPS - Success") + set(HAVE_PIXMAPS 1) + endif() + +endif(WITH_OPENGL) + +set(OPENGL_X11 0) +set(OPENGL_AQUA 0) +set(OPENGL_WINDOWS 0) +if(WITH_OPENGL) + if(APPLE) + set(OPENGL_AQUA 1) + set(OPENGL_AGL 1) + elseif(WIN32) + set(OPENGL_WINDOWS 1) + else() + set(OPENGL_X11 1) + endif() +endif() diff --git a/cmake/modules/Configure.cmake b/cmake/modules/Configure.cmake new file mode 100644 index 00000000000..0b6db9ba25b --- /dev/null +++ b/cmake/modules/Configure.cmake @@ -0,0 +1,190 @@ +include(CheckIncludeFile) +include(CheckSymbolExists) +include(CheckCSourceCompiles) + +check_include_file(limits.h HAVE_LIMITS_H) +check_include_file(termio.h HAVE_TERMIO_H) +check_include_file(termios.h HAVE_TERMIOS_H) +if(NOT MSVC) + check_include_file(unistd.h HAVE_UNISTD_H) +else() + # unistd.h in stocked in thirdparty/msvc/ + set(HAVE_UNISTD_H 1) +endif() +check_include_file(values.h HAVE_VALUES_H) +check_include_file(sys/ioctl.h HAVE_SYS_IOCTL_H) +check_include_file(sys/mtio.h HAVE_SYS_MTIO_H) +check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H) +check_include_file(sys/time.h HAVE_SYS_TIME_H) +check_include_file(time.h HAVE_TIME_H) +check_include_file(sys/timeb.h HAVE_SYS_TIMEB_H) +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(sys/utsname.h HAVE_SYS_UTSNAME_H) +check_include_file(g2c.h HAVE_G2C_H) +check_include_file(f2c.h HAVE_F2C_H) + +if(MSVC) + set(HAVE_PTHREAD_H 0) + set(HAVE_REGEX_H 0) + set(HAVE_LIBINTL_H 0) + set(HAVE_LANGINFO_H 0) + set(HAVE_DBM_H 0) +else() + check_include_file(pthread.h HAVE_PTHREAD_H) + check_include_file(regex.h HAVE_REGEX_H) + check_include_file(libintl.h HAVE_LIBINTL_H) + check_include_file(langinfo.h HAVE_LANGINFO_H) + check_include_file(dbm.h HAVE_DBM_H) +endif() +# +# # set(CMAKE_REQUIRED_INCLUDES "${FFTW_INCLUDE_DIR}") check_target(ICONV +# HAVE_ICONV_H) check_target(BZIP2 HAVE_BZLIB_H) check_target(ZLIB HAVE_ZLIB_H) +# check_target(LIBJPEG HAVE_JPEGLIB_H) check_target(LIBPNG HAVE_PNG_H) +# check_target(TIFF HAVE_TIFFIO_H) check_target(GEOS HAVE_GEOS) +# check_target(GDAL HAVE_GDAL) check_target(GDAL HAVE_OGR) check_target(SQLITE +# HAVE_SQLITE) +# +# check_target(PROJ HAVE_PROJ_H) +# +# check_target(BLAS HAVE_LIBBLAS) check_target(BLAS HAVE_CBLAS_H) +# +# check_target(LAPACK HAVE_LIBLAPACK) check_target(LAPACK HAVE_CLAPACK_H) +# +# check_target(FREETYPE HAVE_FT2BUILD_H) check_target(POSTGRES HAVE_POSTGRES) +# check_target(ODBC HAVE_SQL_H) +# +# if(TARGET POSTGRES) try_compile( HAVE_PQCMDTUPLES ${CMAKE_CURRENT_BINARY_DIR} +# ${CMAKE_SOURCE_DIR}/cmake/tests/have_pqcmdtuples.c CMAKE_FLAGS +# "-DINCLUDE_DIRECTORIES:PATH=${PostgreSQL_INCLUDE_DIR}" "-w" +# "-DLINK_LIBRARIES:STRING=${PostgreSQL_LIBRARY}" OUTPUT_VARIABLE +# COMPILE_HAVE_PQCMDTUPLES) if(NOT COMPILE_HAVE_PQCMDTUPLES) message( +# "Performing Test HAVE_PQCMDTUPLES - Failed\n +# COMPILE_OUTPUT:${COMPILE_HAVE_PQCMDTUPLES}\n" ) else() message(STATUS +# "Performing Test HAVE_PQCMDTUPLES - Success") set(HAVE_PQCMDTUPLES 1) endif() +# endif() +# +# if(MSVC) check_target(PCRE HAVE_PCRE_H) endif() +# +# check_target(POSTGRES HAVE_LIBPQ_FE_H) + +# Whether or not we are using G_socks for display communications +set(USE_G_SOCKS 0) + +if(WITH_LARGEFILES) + set(HAVE_LARGEFILES 1) +else() + set(HAVE_LARGEFILES 0) +endif() + +if(MSVC) + set(GID_TYPE int) + set(UID_TYPE int) + set(UID_TYPE int) + set(RETSIGTYPE "void") +else() + set(RETSIGTYPE "int") +endif() + +# #######################TODO######################## +# no target ATLAS in thirdpary/CMakeLists.txt check_target(ATLAS HAVE_LIBATLAS) + +set(USE_NLS 0) +if(WITH_NLS) + set(USE_NLS 1) +endif() +set(HAVE_READLINE_READLINE_H 0) + +if(MSVC) + set(PID_TYPE int) +endif() + +set(_OE_SOCKETS 0) +set(USE_DELTA_FOR_TZ 0) +set(_REENTRANT 0) +# #######################TODO######################## + +set(X_DISPLAY_MISSING 1) +if(TARGET X11) + set(X_DISPLAY_MISSING 0) +endif() + +# used in config.cmake.in +set(STATIC_BUILD 0) +if(NOT BUILD_SHARED_LIBS) + set(STATIC_BUILD 1) +endif() + +# used in config.cmake.in +set(GDEBUG 0) +if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + set(GDEBUG 1) +endif() + +set(CMAKE_REQUIRED_FLAGS ${CMAKE_C_FLAGS}) + +check_c_source_compiles( + " +int main(int argc, char *argv[]) +{ +long long int x; +return 0; +} +" + HAVE_LONG_LONG_INT) + +check_c_source_compiles( + " +#include +#include +#include +int main() { +struct tm *tp; +; return 0; } +" + TIME_WITH_SYS_TIME) + +check_symbol_exists(gethostname "unistd.h" HAVE_GETHOSTNAME) +check_symbol_exists(gettimeofday "sys/time.h" HAVE_GETTIMEOFDAY) +check_symbol_exists(time "time.h" HAVE_TIME) +check_symbol_exists(asprintf "stdio.h" HAVE_ASPRINTF) +check_symbol_exists(putenv "stdlib.h" HAVE_PUTENV) +check_symbol_exists(setenv "stdlib.h" HAVE_SETENV) +check_symbol_exists(socket "sys/socket.h" HAVE_SOCKET) +check_symbol_exists(ftime "sys/timeb.h" HAVE_FTIME) +check_symbol_exists(lseek "unistd.h" HAVE_LSEEK) +check_symbol_exists(uname "sys/utsname.h" HAVE_UNAME) +check_symbol_exists(seteuid "unistd.h" HAVE_SETEUID) +check_symbol_exists(setpriority "sys/resource.h" HAVE_SETPRIORITY) +check_symbol_exists(setreuid "unistd.h" HAVE_SETREUID) +check_symbol_exists(setruid "unistd.h" HAVE_SETRUID) +check_symbol_exists(setpgrp "unistd.h" SETPGRP_VOID) +check_symbol_exists(drand48 "stdlib.h" HAVE_DRAND48) +check_symbol_exists(nanosleep "time.h" HAVE_NANOSLEEP) +check_symbol_exists(fseeko "stdio.h" HAVE_FSEEKO) + +# set(HAVE_PBUFFERS 0) set(HAVE_PIXMAPS 0) if(WITH_OPENGL) try_compile( +# HAVE_PBUFFERS ${CMAKE_CURRENT_BINARY_DIR} +# ${CMAKE_SOURCE_DIR}/cmake/tests/have_pbuffer.c CMAKE_FLAGS +# "-DINCLUDE_DIRECTORIES:PATH=${OPENGL_INCLUDE_DIR}" "-w" +# "-DLINK_LIBRARIES:STRING=${OPENGL_LIBRARIES}" OUTPUT_VARIABLE +# COMPILE_HAVE_PBUFFERS) if(NOT COMPILE_HAVE_PBUFFERS) message( FATAL_ERROR +# "Performing Test HAVE_PBUFFERS - Failed\n +# COMPILE_OUTPUT:${COMPILE_HAVE_PBUFFERS}\n" ) else() message(STATUS "Performing +# Test HAVE_PBUFFERS - Success") set(HAVE_PBUFFERS 1) endif() +# +# try_compile( HAVE_PIXMAPS ${CMAKE_CURRENT_BINARY_DIR} +# ${CMAKE_SOURCE_DIR}/cmake/tests/have_pixmaps.c CMAKE_FLAGS +# "-DINCLUDE_DIRECTORIES:PATH=${OPENGL_INCLUDE_DIR}" "-w" +# "-DLINK_LIBRARIES:STRING=${OPENGL_LIBRARIES}" OUTPUT_VARIABLE +# COMPILE_HAVE_PIXMAPS) +# +# if(NOT COMPILE_HAVE_PIXMAPS) message( FATAL_ERROR "Performing Test +# HAVE_PIXMAPS - Failed\n COMPILE_OUTPUT:${COMPILE_HAVE_PIXMAPS}\n" ) else() +# message(STATUS "Performing Test HAVE_PIXMAPS - Success") set(HAVE_PIXMAPS 1) +# endif() +# +# endif(WITH_OPENGL) +# +# set(OPENGL_X11 0) set(OPENGL_AQUA 0) set(OPENGL_WINDOWS 0) if(WITH_OPENGL) +# if(APPLE) set(OPENGL_AQUA 1) set(OPENGL_AGL 1) elseif(WIN32) +# set(OPENGL_WINDOWS 1) else() set(OPENGL_X11 1) endif() endif() diff --git a/cmake/modules/build_gui_in_subdir.cmake b/cmake/modules/build_gui_in_subdir.cmake new file mode 100644 index 00000000000..752df2922fd --- /dev/null +++ b/cmake/modules/build_gui_in_subdir.cmake @@ -0,0 +1,117 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: build_gui_in_subdir is the cmake function that builds g.gui.* modules +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +#]] + +function(build_gui_in_subdir dir_name) + set(G_NAME ${dir_name}) + set(G_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${G_NAME}) + set(G_TARGET_NAME g.gui.${G_NAME}) + + set(HTML_FILE_NAME ${G_TARGET_NAME}) + + file(GLOB PYTHON_FILES "${G_SRC_DIR}/*.py") + if(NOT PYTHON_FILES) + message(FATAL_ERROR "[${G_TARGET_NAME}]: No PYTHON_FILES found.") + endif() + + set(SRC_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${G_NAME}/${G_TARGET_NAME}.py) + + if(NOT EXISTS ${SRC_SCRIPT_FILE}) + message(FATAL_ERROR "${SRC_SCRIPT_FILE} does not exists") + endif() + + set(SCRIPT_EXT "") + if(WIN32) + set(SCRIPT_EXT ".py") + endif() + set(GUI_STAMP_FILE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${G_NAME}.stamp) + + add_custom_command( + OUTPUT ${GUI_STAMP_FILE} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${GISBASE}/gui/wxpython/${G_NAME}/ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PYTHON_FILES} + ${GISBASE}/gui/wxpython/${G_NAME}/ + COMMAND ${CMAKE_COMMAND} -E touch ${GUI_STAMP_FILE}) + + set(OUT_SCRIPT_FILE ${GISBASE}/scripts/${G_TARGET_NAME}${SCRIPT_EXT}) + add_custom_command( + OUTPUT ${OUT_SCRIPT_FILE} + COMMAND + ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR} + -DBINARY_DIR=${CMAKE_BINARY_DIR} -DSRC_SCRIPT_FILE=${SRC_SCRIPT_FILE} + -DG_NAME=${G_TARGET_NAME} -DGISBASE=${GISBASE} -P + ${CMAKE_SOURCE_DIR}/cmake/copy_g_gui_module.cmake + DEPENDS g.parser ${SRC_SCRIPT_FILE}) + + if(WITH_DOCS) + + file(GLOB IMG_FILES ${G_SRC_DIR}/*.png ${G_SRC_DIR}/*.jpg) + if(IMG_FILES) + set(copy_images_command ${CMAKE_COMMAND} -E copy ${IMG_FILES} + ${GISBASE}/docs/html/) + endif() + + set(HTML_FILE ${G_SRC_DIR}/${G_TARGET_NAME}.html) + if(EXISTS ${HTML_FILE}) + install(FILES ${GISBASE}/docs/html/${G_TARGET_NAME}.html + DESTINATION docs/html) + else() + set(HTML_FILE) + file(GLOB html_files ${G_SRC_DIR}/*.html) + if(html_files) + message( + FATAL_ERROR + "${html_file} does not exists. ${G_SRC_DIR} \n ${GISBASE}/scripts| ${G_TARGET_NAME}" + ) + endif() + endif() + + set(TMP_HTML_FILE + ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${G_TARGET_NAME}.tmp.html) + set(OUT_HTML_FILE ${GISBASE}/docs/html/${G_TARGET_NAME}.html) + set(GUI_HTML_FILE ${GISBASE}/docs/html/wxGUI.${G_NAME}.html) + + add_custom_command( + OUTPUT ${OUT_HTML_FILE} + COMMAND + ${grass_env_command} ${PYTHON_EXECUTABLE} + ${GISBASE}/scripts/${G_TARGET_NAME}${SCRIPT_EXT} --html-description > + ${TMP_HTML_FILE} + COMMAND ${grass_env_command} ${PYTHON_EXECUTABLE} ${MKHTML_PY} + ${G_TARGET_NAME} ${GRASS_VERSION_DATE} > ${OUT_HTML_FILE} + COMMENT "Creating ${OUT_HTML_FILE}" + COMMAND ${copy_images_command} + COMMAND ${CMAKE_COMMAND} -E remove ${TMP_HTML_FILE} + COMMAND ${grass_env_command} ${PYTHON_EXECUTABLE} ${MKHTML_PY} + ${G_TARGET_NAME} ${GRASS_VERSION_DATE} > ${GUI_HTML_FILE} + COMMENT "Creating ${GUI_HTML_FILE}" + DEPENDS ${OUT_SCRIPT_FILE} GUI_WXPYTHON LIB_PYTHON) + + install(FILES ${OUT_HTML_FILE} DESTINATION docs/html/) + + endif() # WITH_DOCS + + add_custom_target( + ${G_TARGET_NAME} DEPENDS ${GUI_STAMP_FILE} ${OUT_SCRIPT_FILE} + ${OUT_HTML_FILE}) + + set(modules_list + "${G_TARGET_NAME};${modules_list}" + CACHE INTERNAL "list of modules") + + set_target_properties(${G_TARGET_NAME} PROPERTIES FOLDER gui) + + if(WIN32) + install(PROGRAMS ${GISBASE}/scripts/${G_TARGET_NAME}.bat + DESTINATION scripts) + endif() + + install(PROGRAMS ${GISBASE}/scripts/${G_TARGET_NAME}${SCRIPT_EXT} + DESTINATION scripts) + +endfunction() diff --git a/cmake/modules/build_library_in_subdir.cmake b/cmake/modules/build_library_in_subdir.cmake new file mode 100644 index 00000000000..739d2f9c76c --- /dev/null +++ b/cmake/modules/build_library_in_subdir.cmake @@ -0,0 +1,19 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: This is the macro to make grass libraries through build_module function. +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +#]] + +macro(build_library_in_subdir dir_name) + set(extra_args ${ARGN}) + if("NAME" IN_LIST extra_args) + build_module(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${dir_name} ${ARGN}) + else() + get_filename_component(g_name ${dir_name} NAME) + # message("dir_name=${dir_name} |g_name= ${g_name}") + build_module(NAME grass_${g_name} SRC_DIR + ${CMAKE_CURRENT_SOURCE_DIR}/${dir_name} ${ARGN}) + endif() +endmacro() diff --git a/cmake/modules/build_module.cmake b/cmake/modules/build_module.cmake new file mode 100644 index 00000000000..ac644f7719d --- /dev/null +++ b/cmake/modules/build_module.cmake @@ -0,0 +1,288 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: This is the main function that builds all grass libraries (prefixed with grass_) + and grass exeuctables. This cmake function is tailored to meet requirement of grass + gnu make rules +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +#]] + +include(GenerateExportHeader) +function(build_module) + cmake_parse_arguments( + G + "EXE" + "NAME;SRC_DIR;SRC_REGEX;RUNTIME_OUTPUT_DIR;PACKAGE;HTML_FILE_NAME" + "SOURCES;INCLUDES;DEPENDS;OPTIONAL_DEPENDS;PRIMARY_DEPENDS;DEFS;HEADERS;TEST_SOURCES" + ${ARGN}) + + if(NOT G_NAME) + message(FATAL_ERROR "G_NAME empty") + endif() + + foreach(PRIMARY_DEPEND ${G_PRIMARY_DEPENDS}) + if(NOT TARGET ${PRIMARY_DEPEND}) + message( + STATUS "${G_NAME} disabled because ${PRIMARY_DEPEND} is not available") + return() + else() + list(APPEND G_DEPENDS ${PRIMARY_DEPEND}) + endif() + endforeach() + + if(NOT G_SRC_REGEX) + set(G_SRC_REGEX "*.c") + endif() + + if(NOT G_SRC_DIR) + set(G_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + set(html_file "${G_SRC_DIR}/${G_NAME}.html") + + foreach(G_HEADER ${G_HEADERS}) + if(EXISTS "${G_SRC_DIR}/${G_HEADER}") + file(COPY ${G_SRC_DIR}/${G_HEADER} DESTINATION "${GISBASE}/include/grass") + else() + file( + GLOB header_list_from_glob + LIST_DIRECTORIES false + "${G_SRC_DIR}/${G_HEADER}") + if(NOT header_list_from_glob) + message( + FATAL_ERROR + "MUST copy '${G_SRC_DIR}/${G_HEADER}' to ${GISBASE}/include/grass") + endif() + foreach(header_I ${header_list_from_glob}) + file(COPY ${header_I} DESTINATION "${GISBASE}/include/grass") + endforeach() + endif() + endforeach() + + if(NOT G_SOURCES) + file(GLOB ${G_NAME}_SRCS "${G_SRC_DIR}/${G_SRC_REGEX}") + else() + set(${G_NAME}_SRCS ${G_SOURCES}) + endif() + + set(RUN_HTML_DESCR TRUE) + # Auto set if to run RUN_HTML_DESCR + if(G_EXE) + set(RUN_HTML_DESCR TRUE) + if(G_RUNTIME_OUTPUT_DIR) + set(RUN_HTML_DESCR FALSE) + endif() + # g.parser and some others does not have --html-description. + if(${G_NAME} IN_LIST NO_HTML_DESCR_TARGETS) + set(RUN_HTML_DESCR FALSE) + endif() + else() + set(RUN_HTML_DESCR FALSE) + endif() + + set(install_dest "") + if(NOT G_RUNTIME_OUTPUT_DIR) + if(G_EXE) + set(G_RUNTIME_OUTPUT_DIR "${GISBASE}/bin") + set(install_dest "bin") + else() + set(G_RUNTIME_OUTPUT_DIR "${GISBASE}/lib") + set(install_dest "lib") + endif() + else() + set(install_dest "${G_RUNTIME_OUTPUT_DIR}") + set(G_RUNTIME_OUTPUT_DIR "${GISBASE}/${install_dest}") + endif() + + if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${G_RUNTIME_OUTPUT_DIR}) + endif() + + if(G_EXE) + add_executable(${G_NAME} ${${G_NAME}_SRCS}) + if("${G_NAME}" MATCHES "^v.*") + set_target_properties(${G_NAME} PROPERTIES FOLDER vector) + elseif("${G_NAME}" MATCHES "^r.*") + set_target_properties(${G_NAME} PROPERTIES FOLDER raster) + else() + set_target_properties(${G_NAME} PROPERTIES FOLDER bin) + endif() + set(default_html_file_name ${G_NAME}) + set(PGM_NAME ${G_NAME}) + if(WIN32) + set(PGM_NAME ${G_NAME}.exe) + endif() + + set(modules_list + "${G_NAME};${modules_list}" + CACHE INTERNAL "list of modules") + + else() + add_library(${G_NAME} ${${G_NAME}_SRCS}) + set_target_properties( + ${G_NAME} + PROPERTIES FOLDER lib + VERSION ${GRASS_VERSION_NUMBER} + SOVERSION ${GRASS_VERSION_MAJOR}) + set(export_file_name "${GISBASE}/include/export/${G_NAME}_export.h") + # Default is to use library target name without grass_ prefix + string(REPLACE "grass_" "" default_html_file_name ${G_NAME}) + set(PGM_NAME ${default_html_file_name}) + + generate_export_header(${G_NAME} STATIC_DEFINE "STATIC_BUILD" + EXPORT_FILE_NAME ${export_file_name}) + endif() + + if(G_HTML_FILE_NAME) + set(HTML_FILE_NAME ${G_HTML_FILE_NAME}) + else() + set(HTML_FILE_NAME ${default_html_file_name}) + endif() + + get_property(MODULE_LIST GLOBAL PROPERTY MODULE_LIST) + set_property(GLOBAL PROPERTY MODULE_LIST "${MODULE_LIST};${G_NAME}") + + add_dependencies(${G_NAME} copy_header) + + foreach(G_OPTIONAL_DEPEND ${G_OPTIONAL_DEPENDS}) + if(TARGET ${G_OPTIONAL_DEPEND}) + add_dependencies(${G_NAME} ${G_OPTIONAL_DEPEND}) + endif() + endforeach() + foreach(G_DEPEND ${G_DEPENDS}) + if(NOT TARGET ${G_DEPEND}) + message(FATAL_ERROR "${G_DEPEND} not a target") + break() + endif() + + add_dependencies(${G_NAME} ${G_DEPEND}) + + set(${G_NAME}_INCLUDE_DIRS) + list(APPEND ${G_NAME}_INCLUDE_DIRS "${G_SRC_DIR}") + foreach(G_INCLUDE ${G_INCLUDES}) + list(APPEND ${G_NAME}_INCLUDE_DIRS "${G_INCLUDE}") + endforeach() + + if(${G_NAME}_INCLUDE_DIRS) + list(REMOVE_DUPLICATES ${G_NAME}_INCLUDE_DIRS) + endif() + + target_include_directories(${G_NAME} PUBLIC ${${G_NAME}_INCLUDE_DIRS}) + endforeach() + + foreach(G_DEF ${G_DEFS}) + target_compile_definitions(${G_NAME} PUBLIC "${G_DEF}") + endforeach() + + set(package_define) + if(NOT G_PACKAGE) + if(G_EXE) + set(package_define "grassmods") + else() + set(package_define "grasslibs") + endif() + else() + if(NOT G_PACKAGE STREQUAL "NONE") + set(package_define ${G_PACKAGE}) + endif() + endif() + + target_compile_definitions(${G_NAME} + PRIVATE "-DPACKAGE=\"${package_define}\"") + + foreach(dep ${G_DEPENDS} ${G_OPTIONAL_DEPENDS}) + if(TARGET ${dep}) + get_target_property(interface_def ${dep} INTERFACE_COMPILE_DEFINITIONS) + if(interface_def) + target_compile_definitions(${G_NAME} PRIVATE "${interface_def}") + endif() + target_link_libraries(${G_NAME} ${dep}) + elseif(OpenMP_C_FOUND) + target_link_libraries(${G_NAME} OpenMP::OpenMP_C) + endif() + endforeach() + + # To use this property later in build_docs + set(PGM_EXT "") + if(WIN32) + if(G_EXE) + set(PGM_EXT ".exe") + endif() + endif() + + if(WITH_DOCS) + + set(G_HTML_FILE_NAME "${HTML_FILE_NAME}.html") + + set(html_file ${G_SRC_DIR}/${G_HTML_FILE_NAME}) + set(HTML_FILE) + set(no_docs_list "grass_sqlp;echo;clean_temp;lock;run") + + if(EXISTS ${html_file}) + set(HTML_FILE ${html_file}) + install(FILES ${GISBASE}/docs/html/${G_HTML_FILE_NAME} + DESTINATION docs/html) + else() + file(GLOB html_files ${G_SRC_DIR}/*.html) + if(html_files) + if(NOT ${target_name} IN_LIST no_docs_list) + message( + FATAL_ERROR + "${html_file} does not exists. ${G_SRC_DIR} \n ${G_RUNTIME_OUTPUT_DIR} | ${target_name}" + ) + endif() + endif() + endif() + + if(NOT HTML_FILE) + return() + endif() + # message("HTML_FILE=${HTML_FILE}") + + get_filename_component(HTML_FILE_NAME ${HTML_FILE} NAME) + get_filename_component(PGM_SOURCE_DIR ${HTML_FILE} PATH) + + string(REPLACE ".html" "" PGM_NAME "${HTML_FILE_NAME}") + string(REPLACE ".html" ".tmp.html" TMP_HTML_NAME ${HTML_FILE_NAME}) + set(TMP_HTML_FILE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TMP_HTML_NAME}) + set(OUT_HTML_FILE ${GISBASE}/docs/html/${HTML_FILE_NAME}) + + set(PGM_EXT "") + if(WIN32) + set(PGM_EXT ".exe") + endif() + + if(RUN_HTML_DESCR) + set(html_descr_command ${G_NAME}${PGM_EXT} --html-description) + else() + set(html_descr_command ${CMAKE_COMMAND} -E echo) + endif() + + file(GLOB IMG_FILES ${G_SRC_DIR}/*.png ${G_SRC_DIR}/*.jpg) + if(IMG_FILES) + set(copy_images_command ${CMAKE_COMMAND} -E copy ${IMG_FILES} + ${GISBASE}/docs/html/) + endif() + + add_custom_command( + TARGET ${G_NAME} + POST_BUILD + COMMAND ${grass_env_command} ${html_descr_command} > ${TMP_HTML_FILE} + COMMAND ${grass_env_command} ${PYTHON_EXECUTABLE} ${MKHTML_PY} ${PGM_NAME} + > ${OUT_HTML_FILE} + COMMAND ${copy_images_command} + COMMAND ${CMAKE_COMMAND} -E remove ${TMP_HTML_FILE} + COMMENT "Creating ${OUT_HTML_FILE}") + + endif() # WITH_DOCS + + foreach(test_SOURCE ${G_TEST_SOURCES}) + add_test(NAME ${G_NAME}-test + COMMAND ${grass_env_command} ${PYTHON_EXECUTABLE} + ${G_SRC_DIR}/testsuite/${test_SOURCE}) + message("[build_module] ADDING TEST ${G_NAME}-test") + endforeach() + + install(TARGETS ${G_NAME} DESTINATION ${install_dest}) + +endfunction() diff --git a/cmake/modules/build_program.cmake b/cmake/modules/build_program.cmake new file mode 100644 index 00000000000..69ea000337e --- /dev/null +++ b/cmake/modules/build_program.cmake @@ -0,0 +1,11 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: Shortcut macro to call build_module with EXE argument set +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +#]] + +macro(build_program) + build_module(${ARGN} EXE) +endmacro() diff --git a/cmake/modules/build_program_in_subdir.cmake b/cmake/modules/build_program_in_subdir.cmake new file mode 100644 index 00000000000..5f7bccd192d --- /dev/null +++ b/cmake/modules/build_program_in_subdir.cmake @@ -0,0 +1,20 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: CMake macro to build a grass executable (program) under sub directory + which is passed as argument to macro +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +#]] + +macro(build_program_in_subdir dir_name) + set(extra_args ${ARGN}) + if("NAME" IN_LIST extra_args) + # message("dir_name=${dir_name} ${extra_args}") + build_program(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${dir_name} ${ARGN}) + else() + get_filename_component(pgm_name ${dir_name} NAME) + build_program(NAME ${pgm_name} SRC_DIR + ${CMAKE_CURRENT_SOURCE_DIR}/${dir_name} ${ARGN}) + endif() +endmacro() diff --git a/cmake/modules/build_script_in_subdir.cmake b/cmake/modules/build_script_in_subdir.cmake new file mode 100644 index 00000000000..f6a439fd9db --- /dev/null +++ b/cmake/modules/build_script_in_subdir.cmake @@ -0,0 +1,104 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: A CMake function that builds grass python script modules +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +#]] + +function(build_script_in_subdir dir_name) + # build_py_module(NAME ${dir_name}) + set(G_NAME ${dir_name}) + + set(G_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${G_NAME}) + + file(GLOB PYTHON_FILES "${G_SRC_DIR}/*.py") + if(NOT PYTHON_FILES) + message(FATAL_ERROR "[${G_NAME}]: No PYTHON_FILES found.") + endif() + + set(SRC_SCRIPT_FILE ${G_SRC_DIR}/${G_NAME}.py) + + if(NOT EXISTS ${SRC_SCRIPT_FILE}) + message(FATAL_ERROR "${SRC_SCRIPT_FILE} does not exists") + return() + endif() + + set(SCRIPT_EXT "") + if(WIN32) + set(SCRIPT_EXT ".py") + endif() + + set(TRANSLATE_C_FILE + ${CMAKE_SOURCE_DIR}/locale/scriptstrings/${G_NAME}_to_translate.c) + + add_custom_command( + OUTPUT ${TRANSLATE_C_FILE} + COMMAND + ${CMAKE_COMMAND} -DBINARY_DIR=${CMAKE_BINARY_DIR} -DG_NAME=${G_NAME} + -DSRC_SCRIPT_FILE=${SRC_SCRIPT_FILE} -DSOURCE_DIR=${CMAKE_SOURCE_DIR} + -DOUTPUT_FILE=${TRANSLATE_C_FILE} -P + ${CMAKE_SOURCE_DIR}/cmake/locale_strings.cmake + DEPENDS g.parser) + + set(HTML_FILE_NAME ${G_NAME}) + set(OUT_HTML_FILE "") + + if(WITH_DOCS) + + file(GLOB IMG_FILES ${G_SRC_DIR}/*.png ${G_SRC_DIR}/*.jpg) + if(IMG_FILES) + set(copy_images_command ${CMAKE_COMMAND} -E copy ${IMG_FILES} + ${GISBASE}/docs/html/) + endif() + + set(HTML_FILE ${G_SRC_DIR}/${G_NAME}.html) + if(EXISTS ${HTML_FILE}) + install(FILES ${GISBASE}/docs/html/${G_NAME}.html DESTINATION docs/html) + else() + set(HTML_FILE) + file(GLOB html_files ${G_SRC_DIR}/*.html) + if(html_files) + message( + FATAL_ERROR + "${html_file} does not exists. ${G_SRC_DIR} \n ${GISBASE}/scripts| ${G_NAME}" + ) + endif() + endif() + + set(TMP_HTML_FILE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${G_NAME}.tmp.html) + set(OUT_HTML_FILE ${GISBASE}/docs/html/${G_NAME}.html) + + add_custom_command( + OUTPUT ${OUT_HTML_FILE} + COMMAND + ${grass_env_command} ${PYTHON_EXECUTABLE} + ${GISBASE}/scripts/${G_NAME}${SCRIPT_EXT} --html-description > + ${TMP_HTML_FILE} + COMMAND ${grass_env_command} ${PYTHON_EXECUTABLE} ${MKHTML_PY} ${G_NAME} > + ${OUT_HTML_FILE} + COMMAND ${copy_images_command} + COMMAND ${CMAKE_COMMAND} -E remove ${TMP_HTML_FILE} + COMMENT "Creating ${OUT_HTML_FILE}" + DEPENDS ${TRANSLATE_C_FILE} LIB_PYTHON) + + install(FILES ${OUT_HTML_FILE} DESTINATION docs/html/) + + endif() # WITH_DOCS + + add_custom_target(${G_NAME} DEPENDS ${TRANSLATE_C_FILE} ${OUT_HTML_FILE}) + + set(modules_list + "${G_NAME};${modules_list}" + CACHE INTERNAL "list of modules") + + set_target_properties(${G_NAME} PROPERTIES FOLDER scripts) + + if(WIN32) + install(PROGRAMS ${GISBASE}/scripts/${G_NAME}.bat DESTINATION scripts) + endif() + + install(PROGRAMS ${GISBASE}/scripts/${G_NAME}${SCRIPT_EXT} + DESTINATION scripts) + +endfunction() diff --git a/cmake/modules/check_target.cmake b/cmake/modules/check_target.cmake new file mode 100644 index 00000000000..1d03d29382f --- /dev/null +++ b/cmake/modules/check_target.cmake @@ -0,0 +1,8 @@ +macro(check_target target_name have_define_var) + set(${have_define_var} 0) + if(TARGET ${target_name}) + # message(STATUS "${target_name} package found. Setting ${have_define_var} + # to 1") + set(${have_define_var} 1) + endif() +endmacro() diff --git a/cmake/modules/copy_python_files_in_subdir.cmake b/cmake/modules/copy_python_files_in_subdir.cmake new file mode 100644 index 00000000000..29073d43da4 --- /dev/null +++ b/cmake/modules/copy_python_files_in_subdir.cmake @@ -0,0 +1,41 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: Simply copy python file in given subdirectory + Destination will be relative to GISBASE directory set in root + CMakeLists.txt +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +#]] + +function(copy_python_files_in_subdir dir_name dst_prefix) + cmake_parse_arguments(G "PRE_BUILD;PRE_LINK;POST_BUILD" "TARGET" "" ${ARGN}) + + file(GLOB PY_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${dir_name}/*.py") + + if(DEFINED G_TARGET) + if(${G_PRE_BUILD}) + set(BUILD PRE_BUILD) + elseif(${G_PRE_LINK}) + set(BUILD PRE_LINK) + else() + set(BUILD POST_BUILD) + endif() + add_custom_command( + TARGET ${G_TARGET} + ${BUILD} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${GISBASE}/${dst_prefix}/${dir_name}/ + COMMAND ${CMAKE_COMMAND} -E copy ${PY_FILES} + ${GISBASE}/${dst_prefix}/${dir_name}/) + else() + string(REPLACE "/" "_" targ_name ${dir_name}) + add_custom_target( + python_${targ_name} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${GISBASE}/${dst_prefix}/${dir_name}/ + COMMAND ${CMAKE_COMMAND} -E copy ${PY_FILES} + ${GISBASE}/${dst_prefix}/${dir_name}/) + set_target_properties(python_${targ_name} PROPERTIES FOLDER lib/python) + endif() +endfunction() diff --git a/cmake/modules/get_host_arch.cmake b/cmake/modules/get_host_arch.cmake new file mode 100644 index 00000000000..a7b3e632886 --- /dev/null +++ b/cmake/modules/get_host_arch.cmake @@ -0,0 +1,44 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: Get host system architecuture +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +#]] + +function(get_host_arch var_arch) + set(host_arch_value "x86_64") # default value + + if(WIN32) + if(MSVC) + execute_process( + COMMAND ${CMAKE_C_COMPILER} + ERROR_VARIABLE ev + OUTPUT_VARIABLE ov + OUTPUT_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + + if("${ev}" MATCHES "x86") + set(${host_arch_value} "x86") + else() + set(${host_arch_value} "x86_64") + endif() + + elseif(MINGW) + + else() + message(FATAL_ERROR "compiler/platform is not supported") + endif() # if(MSVC) + + elseif(UNIX) + execute_process( + COMMAND uname -m + ERROR_VARIABLE ev + OUTPUT_VARIABLE ov + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(${host_arch_value} "${ov}") + endif() + + set(${var_arch} + ${host_arch_value} + PARENT_SCOPE) +endfunction() diff --git a/cmake/modules/get_versions.cmake b/cmake/modules/get_versions.cmake new file mode 100644 index 00000000000..e99fd36eae5 --- /dev/null +++ b/cmake/modules/get_versions.cmake @@ -0,0 +1,44 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: Read major, minor patch, date from given version file +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +#]] + +function(get_versions file_path var_major var_minor var_release var_date) + set(version_major 0) + set(version_minor 0) + set(version_release 0) + set(version_date 00000000) + file(STRINGS "${file_path}" grass_version_strings) + list(LENGTH grass_version_strings grass_version_file_length) + + if(grass_version_file_length LESS 3) + message(FATAL_ERROR "include/VERSION is not a valid file") + endif() + + list(GET grass_version_strings 0 version_major) + list(GET grass_version_strings 1 version_minor) + + if(grass_version_file_length GREATER 2) + list(GET grass_version_strings 2 version_release) + endif() + + if(grass_version_file_length GREATER 3) + list(GET grass_version_strings 3 version_date) + endif() + + set(${var_major} + ${version_major} + PARENT_SCOPE) + set(${var_minor} + ${version_minor} + PARENT_SCOPE) + set(${var_release} + ${version_release} + PARENT_SCOPE) + set(${var_date} + ${version_date} + PARENT_SCOPE) +endfunction() diff --git a/cmake/modules/linker.cmake b/cmake/modules/linker.cmake new file mode 100644 index 00000000000..a94f0e11f77 --- /dev/null +++ b/cmake/modules/linker.cmake @@ -0,0 +1,52 @@ +macro(set_alternate_linker linker) + if(NOT "${USE_ALTERNATE_LINKER}" STREQUAL + "${USE_ALTERNATE_LINKER_OLD_CACHED}") + unset(LINKER_EXECUTABLE CACHE) + endif() + find_program(LINKER_EXECUTABLE ld.${USE_ALTERNATE_LINKER} + ${USE_ALTERNATE_LINKER}) + if(LINKER_EXECUTABLE) + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_GREATER_EQUAL 12.0.0) + add_link_options("--ld-path=${LINKER_EXECUTABLE}") + else() + add_link_options("-fuse-ld=${LINKER_EXECUTABLE}") + endif() + elseif( + "${linker}" STREQUAL "mold" + AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" + AND "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 12.1.0) + # GCC before 12.1.0: -fuse-ld does not accept mold as a valid argument, so + # you need to use -B option instead. + get_filename_component(_dir ${LINKER_EXECUTABLE} DIRECTORY) + get_filename_component(_dir ${_dir} DIRECTORY) + if(EXISTS "${_dir}/libexec/mold/ld") + add_link_options(-B "${_dir}/libexec/mold") + else() + message(FATAL_ERROR "Cannot find ${_dir}/libexec/mold/ld") + endif() + else() + add_link_options("-fuse-ld=${USE_ALTERNATE_LINKER}") + endif() + message(STATUS "Using alternative linker: ${LINKER_EXECUTABLE}") + else() + message( + FATAL_ERROR "Cannot find alternative linker ${USE_ALTERNATE_LINKER}") + endif() +endmacro() + +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" + STREQUAL "GNU") + set(USE_ALTERNATE_LINKER + "" + CACHE + STRING + "Use alternate linker. Leave empty for system default; potential alternatives are 'gold', 'lld', 'bfd', 'mold'" + ) + if(NOT "${USE_ALTERNATE_LINKER}" STREQUAL "") + set_alternate_linker(${USE_ALTERNATE_LINKER}) + endif() + set(USE_ALTERNATE_LINKER_OLD_CACHED + ${USE_ALTERNATE_LINKER} + CACHE INTERNAL "Previous value of USE_ALTERNATE_LINKER") +endif() diff --git a/cmake/modules/repo_status.cmake b/cmake/modules/repo_status.cmake new file mode 100644 index 00000000000..ce107aead53 --- /dev/null +++ b/cmake/modules/repo_status.cmake @@ -0,0 +1,80 @@ +#[[ +AUTHOR(S): Rashad Kanavath +PURPOSE: Read git status of grass repository if building from git clone +COPYRIGHT: (C) 2020 by the GRASS Development Team + This program is free software under the GPL (>=v2) + Read the file COPYING that comes with GRASS for details. +#]] + +function(repo_status repo_dir) + set(time_format "%Y-%m-%dT%H:%M:%S+00:00") + set(GRASS_VERSION_GIT + "exported" + PARENT_SCOPE) + set(GRASS_HEADERS_GIT_HASH + ${GRASS_VERSION_NUMBER} + PARENT_SCOPE) + string(TIMESTAMP GRASS_HEADERS_GIT_DATE ${time_format} UTC) + set(GRASS_HEADERS_GIT_DATE + ${GRASS_HEADERS_GIT_DATE} + PARENT_SCOPE) + + if(NOT EXISTS "${repo_dir}/.git") + return() + endif() + find_package(Git) + if(NOT GIT_FOUND) + return() + endif() + + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE git_rev_OV + ERROR_VARIABLE git_rev_EV + RESULT_VARIABLE git_rev_RV) + + if(git_rev_RV) + message(FATAL_ERROR "Error running git ${git_rev_EV}") + else() + string(STRIP ${git_rev_OV} GRASS_VERSION_GIT) + set(GRASS_VERSION_GIT + "${GRASS_VERSION_GIT}" + PARENT_SCOPE) + endif() + + execute_process( + COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%h -- + "${CMAKE_SOURCE_DIR}/include" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE git_hash_OV + ERROR_VARIABLE git_hash_EV + RESULT_VARIABLE git_hash_RV) + + if(git_hash_RV) + message(FATAL_ERROR "Error running git ${git_hash_EV}") + else() + string(STRIP ${git_hash_OV} GRASS_HEADERS_GIT_HASH) + set(GRASS_HEADERS_GIT_HASH + "${GRASS_HEADERS_GIT_HASH}" + PARENT_SCOPE) + endif() + + execute_process( + COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%ct -- + "${CMAKE_SOURCE_DIR}/include" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE git_date_OV + ERROR_VARIABLE git_date_EV + RESULT_VARIABLE git_date_RV) + + if(git_date_RV) + message(FATAL_ERROR "Error running git ${git_date_EV}") + else() + set(ENV{SOURCE_DATE_EPOCH} ${git_date_OV}) + string(TIMESTAMP GRASS_HEADERS_GIT_DATE ${time_format} UTC) + set(GRASS_HEADERS_GIT_DATE + "${GRASS_HEADERS_GIT_DATE}" + PARENT_SCOPE) + endif() +endfunction() diff --git a/cmake/modules/set_compiler_flags.cmake b/cmake/modules/set_compiler_flags.cmake new file mode 100644 index 00000000000..986b405dd2d --- /dev/null +++ b/cmake/modules/set_compiler_flags.cmake @@ -0,0 +1,14 @@ +macro(set_compiler_flags) + if(MSVC) + set(GRASS_C_FLAGS + "/D_CRT_SECURE_NO_WARNINGS /DNOMINMAX /DGRASS_CMAKE_BUILD=1") + set(GRASS_CXX_FLAGS "${GRASS_C_FLAGS}") + else() + set(GRASS_C_FLAGS "-DGRASS_CMAKE_BUILD=1") + set(GRASS_CXX_FLAGS "${GRASS_C_FLAGS}") + endif() + + set(CMAKE_CXX_FLAGS "${GRASS_CXX_FLAGS} ${CMAKE_CXX_FLAGS}") + set(CMAKE_C_FLAGS "${GRASS_C_FLAGS} ${CMAKE_C_FLAGS}") + +endmacro() diff --git a/cmake/tests/have_pbuffer.c b/cmake/tests/have_pbuffer.c new file mode 100644 index 00000000000..595d07f92a0 --- /dev/null +++ b/cmake/tests/have_pbuffer.c @@ -0,0 +1,20 @@ +#include +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char glXCreatePbuffer(); + +int main() +{ + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined(__stub_glXCreatePbuffer) || defined(__stub___glXCreatePbuffer) + choke me +#else + glXCreatePbuffer(); +#endif + ; + return 0; +} diff --git a/cmake/tests/have_pixmaps.c b/cmake/tests/have_pixmaps.c new file mode 100644 index 00000000000..ad46df8c350 --- /dev/null +++ b/cmake/tests/have_pixmaps.c @@ -0,0 +1,23 @@ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char glXCreateGLXPixmap(); below. */ +#include +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char glXCreateGLXPixmap(); + +int main() +{ + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined(__stub_glXCreateGLXPixmap) || defined(__stub___glXCreateGLXPixmap) + choke me +#else + glXCreateGLXPixmap(); +#endif + + ; + return 0; +} diff --git a/cmake/tests/have_pqcmdtuples.c b/cmake/tests/have_pqcmdtuples.c new file mode 100644 index 00000000000..ad4ae92571d --- /dev/null +++ b/cmake/tests/have_pqcmdtuples.c @@ -0,0 +1,9 @@ +#include +int main() +{ + PGresult *res = NULL; + PGconn *conn = PQconnectdb(NULL); + res = PQexec(conn, NULL); + PQcmdTuples(res); + return 0; +} diff --git a/cmake/windows_launch.bat.in b/cmake/windows_launch.bat.in new file mode 100644 index 00000000000..aa03bb369bf --- /dev/null +++ b/cmake/windows_launch.bat.in @@ -0,0 +1,2 @@ +@echo off +"%GRASS_PYTHON%" "%GISBASE%\scripts\@PGM_NAME@.py" %* \ No newline at end of file diff --git a/config.guess b/config.guess index 7f76b6228f7..f6d217a49f8 100755 --- a/config.guess +++ b/config.guess @@ -1,10 +1,10 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2022 Free Software Foundation, Inc. +# Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2022-01-09' +timestamp='2024-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -47,7 +47,7 @@ me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] -Output the configuration name of the system \`$me' is run on. +Output the configuration name of the system '$me' is run on. Options: -h, --help print this help, then exit @@ -60,13 +60,13 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2022 Free Software Foundation, Inc. +Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" -Try \`$me --help' for more information." +Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do @@ -102,8 +102,8 @@ GUESS= # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. -# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still -# use `HOST_CC' if defined, but it is deprecated. +# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still +# use 'HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. @@ -155,6 +155,9 @@ Linux|GNU|GNU/*) set_cc_for_build cat <<-EOF > "$dummy.c" + #if defined(__ANDROID__) + LIBC=android + #else #include #if defined(__UCLIBC__) LIBC=uclibc @@ -162,6 +165,8 @@ Linux|GNU|GNU/*) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu + #elif defined(__LLVM_LIBC__) + LIBC=llvm #else #include /* First heuristic to detect musl libc. */ @@ -169,6 +174,7 @@ Linux|GNU|GNU/*) LIBC=musl #endif #endif + #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" @@ -459,7 +465,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in UNAME_RELEASE=`uname -v` ;; esac - # Japanese Language versions have a version number like `4.1.3-JL'. + # Japanese Language versions have a version number like '4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; @@ -904,7 +910,7 @@ EOF fi ;; *:FreeBSD:*:*) - UNAME_PROCESSOR=`/usr/bin/uname -p` + UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; @@ -966,11 +972,37 @@ EOF GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; + x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-pc-managarm-mlibc" + ;; + *:[Mm]anagarm:*:*) + GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" + ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) - GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + set_cc_for_build + CPU=$UNAME_MACHINE + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __ARM_EABI__ + #ifdef __ARM_PCS_VFP + ABI=eabihf + #else + ABI=eabi + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; + esac + fi + GUESS=$CPU-unknown-linux-$LIBCABI ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be @@ -1036,7 +1068,16 @@ EOF k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; - loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) + kvx:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + kvx:cos:*:*) + GUESS=$UNAME_MACHINE-unknown-cos + ;; + kvx:mbr:*:*) + GUESS=$UNAME_MACHINE-unknown-mbr + ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) @@ -1151,16 +1192,27 @@ EOF ;; x86_64:Linux:*:*) set_cc_for_build + CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then - if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_X32 >/dev/null - then - LIBCABI=${LIBC}x32 - fi + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __i386__ + ABI=x86 + #else + #ifdef __ILP32__ + ABI=x32 + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + x86) CPU=i686 ;; + x32) LIBCABI=${LIBC}x32 ;; + esac fi - GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI + GUESS=$CPU-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC @@ -1180,7 +1232,7 @@ EOF GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) - # If we were able to find `uname', then EMX Unix compatibility + # If we were able to find 'uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; @@ -1321,7 +1373,7 @@ EOF GUESS=ns32k-sni-sysv fi ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; @@ -1367,8 +1419,11 @@ EOF BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; - x86_64:Haiku:*:*) - GUESS=x86_64-unknown-haiku + ppc:Haiku:*:*) # Haiku running on Apple PowerPC + GUESS=powerpc-apple-haiku + ;; + *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) + GUESS=$UNAME_MACHINE-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE @@ -1540,6 +1595,9 @@ EOF *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; + *:Ironclad:*:*) + GUESS=$UNAME_MACHINE-unknown-ironclad + ;; esac # Do we have a guess based on uname results? diff --git a/config.sub b/config.sub index dba16e84c77..2c6a07ab3c3 100755 --- a/config.sub +++ b/config.sub @@ -1,10 +1,10 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2022 Free Software Foundation, Inc. +# Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2022-01-03' +timestamp='2024-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -76,13 +76,13 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2022 Free Software Foundation, Inc. +Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" -Try \`$me --help' for more information." +Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do @@ -130,7 +130,7 @@ IFS=$saved_IFS # Separate into logical components for further validation case $1 in *-*-*-*-*) - echo Invalid configuration \`"$1"\': more than four components >&2 + echo "Invalid configuration '$1': more than four components" >&2 exit 1 ;; *-*-*-*) @@ -145,7 +145,8 @@ case $1 in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ - | storm-chaos* | os2-emx* | rtmk-nova*) + | storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \ + | windows-* ) basic_machine=$field1 basic_os=$maybe_os ;; @@ -943,7 +944,7 @@ $basic_machine EOF IFS=$saved_IFS ;; - # We use `pc' rather than `unknown' + # We use 'pc' rather than 'unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) @@ -1075,7 +1076,7 @@ case $cpu-$vendor in pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) cpu=i586 ;; - pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*) + pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*) cpu=i686 ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) @@ -1180,7 +1181,7 @@ case $cpu-$vendor in case $cpu in 1750a | 580 \ | a29k \ - | aarch64 | aarch64_be \ + | aarch64 | aarch64_be | aarch64c | arm64ec \ | abacus \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ @@ -1199,50 +1200,29 @@ case $cpu-$vendor in | d10v | d30v | dlx | dsp16xx \ | e2k | elxsi | epiphany \ | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \ + | javascript \ | h8300 | h8500 \ | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i*86 | i860 | i960 | ia16 | ia64 \ | ip2k | iq2000 \ | k1om \ + | kvx \ | le32 | le64 \ | lm32 \ - | loongarch32 | loongarch64 | loongarchx32 \ + | loongarch32 | loongarch64 \ | m32c | m32r | m32rle \ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ | m88110 | m88k | maxq | mb | mcore | mep | metag \ | microblaze | microblazeel \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64eb | mips64el \ - | mips64octeon | mips64octeonel \ - | mips64orion | mips64orionel \ - | mips64r5900 | mips64r5900el \ - | mips64vr | mips64vrel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa32r3 | mipsisa32r3el \ - | mipsisa32r5 | mipsisa32r5el \ - | mipsisa32r6 | mipsisa32r6el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64r3 | mipsisa64r3el \ - | mipsisa64r5 | mipsisa64r5el \ - | mipsisa64r6 | mipsisa64r6el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ - | mipstx39 | mipstx39el \ + | mips* \ | mmix \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ + | nanomips* \ | nds32 | nds32le | nds32be \ | nfp \ | nios | nios2 | nios2eb | nios2el \ @@ -1274,6 +1254,7 @@ case $cpu-$vendor in | ubicom32 \ | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \ | vax \ + | vc4 \ | visium \ | w65 \ | wasm32 | wasm64 \ @@ -1285,7 +1266,7 @@ case $cpu-$vendor in ;; *) - echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2 + echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2 exit 1 ;; esac @@ -1306,11 +1287,12 @@ esac # Decode manufacturer-specific aliases for certain operating systems. -if test x$basic_os != x +if test x"$basic_os" != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. +obj= case $basic_os in gnu/linux*) kernel=linux @@ -1341,6 +1323,10 @@ EOF kernel=linux os=`echo "$basic_os" | sed -e 's|linux|gnu|'` ;; + managarm*) + kernel=managarm + os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'` + ;; *) kernel= os=$basic_os @@ -1506,10 +1492,16 @@ case $os in os=eabi ;; *) - os=elf + os= + obj=elf ;; esac ;; + aout* | coff* | elf* | pe*) + # These are machine code file formats, not OSes + obj=$os + os= + ;; *) # No normalization, but not necessarily accepted, that comes below. ;; @@ -1528,12 +1520,15 @@ else # system, and we'll never get to this point. kernel= +obj= case $cpu-$vendor in score-*) - os=elf + os= + obj=elf ;; spu-*) - os=elf + os= + obj=elf ;; *-acorn) os=riscix1.2 @@ -1543,28 +1538,35 @@ case $cpu-$vendor in os=gnu ;; arm*-semi) - os=aout + os= + obj=aout ;; c4x-* | tic4x-*) - os=coff + os= + obj=coff ;; c8051-*) - os=elf + os= + obj=elf ;; clipper-intergraph) os=clix ;; hexagon-*) - os=elf + os= + obj=elf ;; tic54x-*) - os=coff + os= + obj=coff ;; tic55x-*) - os=coff + os= + obj=coff ;; tic6x-*) - os=coff + os= + obj=coff ;; # This must come before the *-dec entry. pdp10-*) @@ -1586,19 +1588,24 @@ case $cpu-$vendor in os=sunos3 ;; m68*-cisco) - os=aout + os= + obj=aout ;; mep-*) - os=elf + os= + obj=elf ;; mips*-cisco) - os=elf + os= + obj=elf ;; - mips*-*) - os=elf + mips*-*|nanomips*-*) + os= + obj=elf ;; or32-*) - os=coff + os= + obj=coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=sysv3 @@ -1607,7 +1614,8 @@ case $cpu-$vendor in os=sunos4.1.1 ;; pru-*) - os=elf + os= + obj=elf ;; *-be) os=beos @@ -1688,10 +1696,12 @@ case $cpu-$vendor in os=uxpv ;; *-rom68k) - os=coff + os= + obj=coff ;; *-*bug) - os=coff + os= + obj=coff ;; *-apple) os=macos @@ -1709,10 +1719,11 @@ esac fi -# Now, validate our (potentially fixed-up) OS. +# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ). + case $os in # Sometimes we do "kernel-libc", so those need to count as OSes. - musl* | newlib* | relibc* | uclibc*) + llvm* | musl* | newlib* | relibc* | uclibc*) ;; # Likewise for "kernel-abi" eabi* | gnueabi*) @@ -1720,6 +1731,9 @@ case $os in # VxWorks passes extra cpu info in the 4th filed. simlinux | simwindows | spe) ;; + # See `case $cpu-$os` validation below + ghcjs) + ;; # Now accept the basic system types. # The portable systems comes first. # Each alternative MUST end in a * to match a version number. @@ -1728,7 +1742,7 @@ case $os in | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ | hiux* | abug | nacl* | netware* | windows* \ - | os9* | macos* | osx* | ios* \ + | os9* | macos* | osx* | ios* | tvos* | watchos* \ | mpw* | magic* | mmixware* | mon960* | lnews* \ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ | aos* | aros* | cloudabi* | sortix* | twizzler* \ @@ -1737,11 +1751,11 @@ case $os in | mirbsd* | netbsd* | dicos* | openedition* | ose* \ | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \ | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \ - | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ - | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | bosx* | nextstep* | cxux* | oabi* \ + | ptx* | ecoff* | winnt* | domain* | vsta* \ | udi* | lites* | ieee* | go32* | aux* | hcos* \ | chorusrdb* | cegcc* | glidix* | serenity* \ - | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | cygwin* | msys* | moss* | proelf* | rtems* \ | midipix* | mingw32* | mingw64* | mint* \ | uxpv* | beos* | mpeix* | udk* | moxiebox* \ | interix* | uwin* | mks* | rhapsody* | darwin* \ @@ -1754,49 +1768,116 @@ case $os in | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ - | fiwix* ) + | fiwix* | mlibc* | cos* | mbr* | ironclad* ) ;; # This one is extra strict with allowed versions sco3.2v2 | sco3.2v[4-9]* | sco5v6*) # Don't forget version if it is 3.2v4 or newer. ;; + # This refers to builds using the UEFI calling convention + # (which depends on the architecture) and PE file format. + # Note that this is both a different calling convention and + # different file format than that of GNU-EFI + # (x86_64-w64-mingw32). + uefi) + ;; none) ;; + kernel* | msvc* ) + # Restricted further below + ;; + '') + if test x"$obj" = x + then + echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2 + fi + ;; + *) + echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 + exit 1 + ;; +esac + +case $obj in + aout* | coff* | elf* | pe*) + ;; + '') + # empty is fine + ;; *) - echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2 + echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 + exit 1 + ;; +esac + +# Here we handle the constraint that a (synthetic) cpu and os are +# valid only in combination with each other and nowhere else. +case $cpu-$os in + # The "javascript-unknown-ghcjs" triple is used by GHC; we + # accept it here in order to tolerate that, but reject any + # variations. + javascript-ghcjs) + ;; + javascript-* | *-ghcjs) + echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. -case $kernel-$os in - linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ - | linux-musl* | linux-relibc* | linux-uclibc* ) +case $kernel-$os-$obj in + linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \ + | linux-mlibc*- | linux-musl*- | linux-newlib*- \ + | linux-relibc*- | linux-uclibc*- ) + ;; + uclinux-uclibc*- ) + ;; + managarm-mlibc*- | managarm-kernel*- ) ;; - uclinux-uclibc* ) + windows*-msvc*-) ;; - -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) + -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \ + | -uclibc*- ) # These are just libc implementations, not actual OSes, and thus # require a kernel. - echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 exit 1 ;; - kfreebsd*-gnu* | kopensolaris*-gnu*) + -kernel*- ) + echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 + exit 1 ;; - vxworks-simlinux | vxworks-simwindows | vxworks-spe) + *-kernel*- ) + echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 + exit 1 ;; - nto-qnx*) + *-msvc*- ) + echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 + exit 1 ;; - os2-emx) + kfreebsd*-gnu*- | kopensolaris*-gnu*-) + ;; + vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) + ;; + nto-qnx*-) + ;; + os2-emx-) ;; - *-eabi* | *-gnueabi*) + *-eabi*- | *-gnueabi*-) ;; - -*) + none--*) + # None (no kernel, i.e. freestanding / bare metal), + # can be paired with an machine code file format + ;; + -*-) # Blank kernel with real OS is always fine. ;; - *-*) - echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + --*) + # Blank kernel and OS with real machine code file format is always fine. + ;; + *-*-*) + echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 exit 1 ;; esac @@ -1879,7 +1960,7 @@ case $vendor in ;; esac -echo "$cpu-$vendor-${kernel:+$kernel-}$os" +echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" exit # Local variables: diff --git a/db/CMakeLists.txt b/db/CMakeLists.txt new file mode 100644 index 00000000000..6693c411aa3 --- /dev/null +++ b/db/CMakeLists.txt @@ -0,0 +1,40 @@ +set(db_drivers grass_gis) +add_subdirectory(drivers) + +build_program_in_subdir(db.columns DEPENDS grass_dbmiclient) +add_dependencies(db.columns ${db_drivers}) + +build_program_in_subdir(db.createdb DEPENDS grass_dbmiclient) +add_dependencies(db.createdb ${db_drivers}) + +build_program_in_subdir(db.describe DEPENDS grass_dbmiclient) +add_dependencies(db.describe ${db_drivers}) + +build_program_in_subdir(db.connect DEPENDS grass_dbmiclient) +add_dependencies(db.connect ${db_drivers}) + +build_program_in_subdir(db.copy DEPENDS grass_dbmiclient) +add_dependencies(db.copy ${db_drivers}) + +build_program_in_subdir(db.execute DEPENDS grass_dbmiclient) +add_dependencies(db.execute ${db_drivers}) + +build_program_in_subdir(db.drivers DEPENDS grass_dbmiclient) +add_dependencies(db.drivers ${db_drivers}) + +build_program_in_subdir(db.databases DEPENDS grass_dbmiclient) +add_dependencies(db.databases ${db_drivers}) + +build_program_in_subdir(db.dropdb DEPENDS grass_dbmiclient) +add_dependencies(db.dropdb ${db_drivers}) + +build_program_in_subdir(db.login DEPENDS grass_dbmiclient) +add_dependencies(db.login ${db_drivers}) + +build_program_in_subdir(db.select DEPENDS grass_dbmiclient) +add_dependencies(db.select ${db_drivers}) + +build_program_in_subdir(db.tables DEPENDS grass_dbmiclient) +add_dependencies(db.tables ${db_drivers}) + +# TODO: PGM = databaseintro diff --git a/db/drivers/CMakeLists.txt b/db/drivers/CMakeLists.txt new file mode 100644 index 00000000000..d6562f2884d --- /dev/null +++ b/db/drivers/CMakeLists.txt @@ -0,0 +1,152 @@ +set(dbf_SRCS + dbf/column.c + dbf/create_table.c + dbf/cursor.c + dbf/db.c + dbf/dbfexe.c + dbf/describe.c + dbf/driver.c + dbf/error.c + dbf/execute.c + dbf/fetch.c + dbf/listtab.c + dbf/main.c + dbf/select.c + dbf/str.c + dbf/table.c) + +set(mysql_SRCS + mysql/create_table.c + mysql/cursor.c + mysql/dbe.c + mysql/describe.c + mysql/driver.c + mysql/error.c + mysql/execute.c + mysql/fetch.c + mysql/index.c + mysql/listtab.c + mysql/main.c + mysql/parse.c + mysql/replace.c + mysql/select.c) + +set(db_drivers) +set(grass_dbstubs_DEFS) +if(MSVC) + set(grass_dbstubs_DEFS "-DDB_DRIVER_C=1") +endif() +build_program_in_subdir( + dbf + SOURCES + ${dbf_SRCS} + DEPENDS + grass_gis + grass_dbmidriver + grass_shape + grass_sqlp + DEFS + "${grass_dbstubs_DEFS}" + HTML_FILE_NAME + grass-dbf + RUNTIME_OUTPUT_DIR + "driver/db/") + +list(APPEND db_drivers dbf) + +build_program_in_subdir( + ogr + DEPENDS + grass_gis + grass_dbmidriver + grass_sqlp + GDAL + DEFS + "${grass_dbstubs_DEFS}" + HTML_FILE_NAME + grass-ogr + RUNTIME_OUTPUT_DIR + "driver/db/") + +list(APPEND db_drivers ogr) + +build_program_in_subdir( + odbc + DEPENDS + grass_gis + grass_dbmidriver + grass_sqlp + DEFS + "${grass_dbstubs_DEFS}" + PRIMARY_DEPENDS + ODBC + HTML_FILE_NAME + grass-odbc + RUNTIME_OUTPUT_DIR + "driver/db/") +if(TARGET ODBC) + list(APPEND db_drivers odbc) +endif() + +build_program_in_subdir( + sqlite + DEPENDS + grass_gis + grass_dbmidriver + grass_sqlp + DEFS + "${grass_dbstubs_DEFS}" + PRIMARY_DEPENDS + SQLITE + HTML_FILE_NAME + grass-sqlite + RUNTIME_OUTPUT_DIR + "driver/db/") + +if(TARGET SQLITE) + list(APPEND db_drivers sqlite) +endif() + +build_program_in_subdir( + postgres + DEPENDS + grass_gis + grass_dbmidriver + grass_sqlp + DEFS + "${grass_dbstubs_DEFS}" + PRIMARY_DEPENDS + POSTGRES + HTML_FILE_NAME + grass-pg + RUNTIME_OUTPUT_DIR + "driver/db/") + +if(TARGET MYSQL) + list(APPEND db_drivers mysql) +endif() + +build_program_in_subdir( + mysql + SOURCES + ${mysql_SRCS} + DEPENDS + grass_gis + grass_dbmidriver + grass_sqlp + DEFS + "${grass_dbstubs_DEFS}" + PRIMARY_DEPENDS + MYSQL + HTML_FILE_NAME + grass-sql + RUNTIME_OUTPUT_DIR + "driver/db/") + +if(TARGET MYSQL) + list(APPEND db_drivers mysql) +endif() + +set(db_drivers + ${db_drivers} + PARENT_SCOPE) diff --git a/db/drivers/odbc/odbc.h b/db/drivers/odbc/odbc.h index 4cd376ee64e..1e14184c2b2 100644 --- a/db/drivers/odbc/odbc.h +++ b/db/drivers/odbc/odbc.h @@ -1,7 +1,7 @@ #ifndef _ODBC_H_ #define _ODBC_H_ -#ifdef __MINGW32__ +#ifdef _WIN32 #include #endif diff --git a/demolocation/grassrc.cmake.in b/demolocation/grassrc.cmake.in new file mode 100644 index 00000000000..7b46331e401 --- /dev/null +++ b/demolocation/grassrc.cmake.in @@ -0,0 +1,4 @@ +GISDBASE: @gisbase_init_dir@ +LOCATION_NAME: demolocation +MAPSET: PERMANENT +GUI: text diff --git a/display/CMakeLists.txt b/display/CMakeLists.txt new file mode 100644 index 00000000000..d52f2754961 --- /dev/null +++ b/display/CMakeLists.txt @@ -0,0 +1,46 @@ +build_program_in_subdir(d.barscale DEPENDS grass_sym grass_display grass_gis) +build_program_in_subdir(d.colorlist DEPENDS grass_gis grass_display) +build_program_in_subdir(d.colortable DEPENDS grass_gis grass_display) +build_program_in_subdir(d.erase DEPENDS grass_gis grass_display) +if(NOT MSVC) + build_program_in_subdir(d.font DEPENDS grass_gis grass_display grass_raster) + # libgen.h does not exists on windows msvc + build_program_in_subdir(d.mon DEPENDS grass_gis grass_display) + copy_python_files_in_subdir(d.mon etc TARGET d.mon POST_BUILD) +endif() +build_program_in_subdir(d.fontlist DEPENDS grass_gis grass_display grass_raster) +build_program_in_subdir(d.geodesic DEPENDS grass_gis grass_display) +build_program_in_subdir(d.graph DEPENDS grass_gis grass_sym grass_display) +build_program_in_subdir(d.grid DEPENDS grass_gis grass_sym grass_gproj + grass_display) +build_program_in_subdir(d.his DEPENDS grass_gis grass_display) +build_program_in_subdir(d.histogram DEPENDS grass_gis grass_display) +build_program_in_subdir(d.info DEPENDS grass_gis grass_display) +build_program_in_subdir(d.labels DEPENDS grass_gis grass_display) +build_program_in_subdir(d.legend DEPENDS grass_gis grass_display grass_raster3d) +build_program_in_subdir(d.legend.vect DEPENDS grass_gis grass_display grass_sym) +build_program_in_subdir(d.linegraph DEPENDS grass_gis grass_display grass_sym) +build_program_in_subdir(d.northarrow DEPENDS grass_gis grass_display grass_sym) +build_program_in_subdir(d.path DEPENDS grass_gis grass_display grass_vector) +build_program_in_subdir(d.profile DEPENDS grass_gis grass_display) +build_program_in_subdir(d.rast DEPENDS grass_gis grass_display grass_raster) +build_program_in_subdir(d.rast.arrow DEPENDS grass_gis grass_raster + grass_display) +build_program_in_subdir(d.rast.num DEPENDS grass_gis grass_display grass_raster) +build_program_in_subdir(d.rgb DEPENDS grass_gis grass_display grass_raster) +build_program_in_subdir(d.rhumbline DEPENDS grass_gis grass_display) +build_program_in_subdir(d.text DEPENDS grass_gis grass_display) +build_program_in_subdir(d.title DEPENDS grass_gis grass_display) +build_program_in_subdir(d.vect DEPENDS grass_gis grass_display grass_vector + grass_sym) +build_program_in_subdir(d.vect.chart DEPENDS grass_gis grass_display + grass_vector grass_sym) +build_program_in_subdir( + d.vect.thematic + DEPENDS + grass_gis + grass_display + grass_vector + grass_sym + grass_arraystats) +build_program_in_subdir(d.where DEPENDS grass_gis grass_display grass_gproj) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/doc/development/submitting/general.md b/doc/development/submitting/general.md index 55e6df6d2b4..48630fd3531 100644 --- a/doc/development/submitting/general.md +++ b/doc/development/submitting/general.md @@ -149,9 +149,10 @@ done manually, you can take an advantage of our [​CI](https://github.com/OSGeo Often there is more than one active release branch. You can also choose to backport only to the closest branch. If you are backporting to other release branches than -just the closets one, make sure you always backport to all the branches between "main" -and the furthest branch you are backporting to. For example, let's say we have -release branches 3.6 and 3.5, if you backport to 3.5, you should backport to 3.6, too. +just the closets one, make sure you always backport to all the branches between +"main" and the furthest branch you are backporting to. For example, let's say we +have release branches 3.6 and 3.5, if you backport to 3.5, you should backport to +3.6, too. Backport only complete fixes. When you are not sure if the fix is complete or if there is an possibility that some details such as wording will change, wait with diff --git a/doc/gui/wxpython/example/README b/doc/gui/wxpython/example/README index 448ff945414..1e619486943 100644 --- a/doc/gui/wxpython/example/README +++ b/doc/gui/wxpython/example/README @@ -24,12 +24,9 @@ or it can be launched from the console. 3. Edit ./gui/wxpython/Makefile: - SRCFILES := $(wildcard icons/*.* scripts/* xml/*) \ -- $(wildcard core/* dbmgr/* gcp/* gmodeler/* ... \ -+ $(wildcard core/* dbmgr/* example/* gcp/* gmodeler/* ... \ - --PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,core dbmgr gcp gmodeler ... \ -+PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,core dbmgr example gcp gmodeler ... \ +SUBDIRS: Add example +SRCFILES: Add example/*py +PYDSTDIRS: Add example 4. Run make (in ./gui/wxpython) diff --git a/doc/gui/wxpython/example/dialogs.py b/doc/gui/wxpython/example/dialogs.py index 8049fbdc612..425ea57a4b2 100644 --- a/doc/gui/wxpython/example/dialogs.py +++ b/doc/gui/wxpython/example/dialogs.py @@ -55,7 +55,7 @@ def __init__(self, parent, title=_("Choose raster map")): def _layout(self): """!Do layout""" self.dataSizer.Add( - item=wx.StaticText(parent=self.panel, label=_("Name of raster map:")), + wx.StaticText(parent=self.panel, label=_("Name of raster map:")), proportion=0, flag=wx.ALL, border=1, diff --git a/doc/gui/wxpython/example/frame.py b/doc/gui/wxpython/example/frame.py index 01a5442789f..7f68642de9f 100644 --- a/doc/gui/wxpython/example/frame.py +++ b/doc/gui/wxpython/example/frame.py @@ -414,7 +414,7 @@ def _setStyle(self, style): else: return - self.textCtrl.SetDefaultStyle(wx.TextAttr(font=self.font)) + self.textCtrl.SetFont(self.font) def _writeLine(self, title, value): """!Formats text (key, value pair) with styles.""" @@ -436,5 +436,5 @@ def WriteStatistics(self, name, statDict): """ self.GetControl().Clear() self._writeRasterTitle(name=name) - for key, value in statDict.iteritems(): + for key, value in statDict.items(): self._writeLine(title=key, value=value) diff --git a/doc/gui/wxpython/example/toolbars.py b/doc/gui/wxpython/example/toolbars.py index c5bc265f125..382672fbe64 100644 --- a/doc/gui/wxpython/example/toolbars.py +++ b/doc/gui/wxpython/example/toolbars.py @@ -112,10 +112,12 @@ def _toolbarData(self): """!Toolbar data""" return self._getToolbarData( ( - ("addRaster", BaseIcons["addRast"].label), - BaseIcons["addRast"], - self.parent.OnSelectRaster, - ), + ( + ("addRaster", BaseIcons["addRast"].label), + BaseIcons["addRast"], + self.parent.OnSelectRaster, + ), + ) ) @@ -135,13 +137,15 @@ def _toolbarData(self): icons = BaseIcons return self._getToolbarData( ( - ("help", icons["help"].label), - icons["help"], - self.parent.OnHelp, - ), - ( - ("quit", icons["quit"].label), - icons["quit"], - self.parent.OnCloseWindow, - ), + ( + ("help", icons["help"].label), + icons["help"], + self.parent.OnHelp, + ), + ( + ("quit", icons["quit"].label), + icons["quit"], + self.parent.OnCloseWindow, + ), + ) ) diff --git a/doc/notebooks/hydrology.ipynb b/doc/notebooks/hydrology.ipynb index f19ce35c436..b9e23acf3c1 100644 --- a/doc/notebooks/hydrology.ipynb +++ b/doc/notebooks/hydrology.ipynb @@ -69,7 +69,9 @@ "\n", "# Add a raster, vector and legend to the map\n", "elev_map.d_rast(map=\"elevation\")\n", - "elev_map.d_legend(raster=\"elevation\", at=(65, 90, 85, 88), fontsize=12, flags=\"b\", title=\"DTM\")\n", + "elev_map.d_legend(\n", + " raster=\"elevation\", at=(65, 90, 85, 88), fontsize=12, flags=\"b\", title=\"DTM\"\n", + ")\n", "\n", "# Display map\n", "elev_map.show()" @@ -90,9 +92,27 @@ "metadata": {}, "outputs": [], "source": [ - "gs.run_command(\"r.fill.dir\", input=\"elevation\", output=\"elev_fill1\", direction=\"dir1\", areas=\"area1\")\n", - "gs.run_command(\"r.fill.dir\", input=\"elev_fill1\", output=\"elev_fill2\", direction=\"dir2\", areas=\"area2\")\n", - "gs.run_command(\"r.fill.dir\", input=\"elev_fill2\", output=\"elev_fill3\", direction=\"dir3\", areas=\"area3\")\n", + "gs.run_command(\n", + " \"r.fill.dir\",\n", + " input=\"elevation\",\n", + " output=\"elev_fill1\",\n", + " direction=\"dir1\",\n", + " areas=\"area1\",\n", + ")\n", + "gs.run_command(\n", + " \"r.fill.dir\",\n", + " input=\"elev_fill1\",\n", + " output=\"elev_fill2\",\n", + " direction=\"dir2\",\n", + " areas=\"area2\",\n", + ")\n", + "gs.run_command(\n", + " \"r.fill.dir\",\n", + " input=\"elev_fill2\",\n", + " output=\"elev_fill3\",\n", + " direction=\"dir3\",\n", + " areas=\"area3\",\n", + ")\n", "gs.mapcalc(\"depr_bin = if((elevation-elev_fill3) < 0., 1, null())\")\n", "gs.run_command(\"r.colors\", map=\"depr_bin\", color=\"blues\")" ] @@ -129,13 +149,15 @@ "metadata": {}, "outputs": [], "source": [ - "gs.run_command(\"r.watershed\", \n", - " elevation=\"elevation@PERMANENT\",\n", - " drainage=\"drainage\", # Drainage Direction\n", - " accumulation=\"flowacc\", # Flow Accumulation\n", - " basin=\"watersheds\",\n", - " stream=\"streams\",\n", - " threshold=80000)\n", + "gs.run_command(\n", + " \"r.watershed\",\n", + " elevation=\"elevation@PERMANENT\",\n", + " drainage=\"drainage\", # Drainage Direction\n", + " accumulation=\"flowacc\", # Flow Accumulation\n", + " basin=\"watersheds\",\n", + " stream=\"streams\",\n", + " threshold=80000,\n", + ")\n", "\n", "# Convert streams raster to vector\n", "gs.run_command(\"r.to.vect\", input=\"streams\", output=\"streams\", type=\"line\")" @@ -160,7 +182,7 @@ "\n", "# We can modify with color table for rasters with `r.colors`.\n", "# Note that if the raster is located in a different mapset (for example,\n", - "# elevation is in PERMANENT, not user1), the `r.colors` will not change \n", + "# elevation is in PERMANENT, not user1), the `r.colors` will not change\n", "# the color in InteractiveMap.\n", "gs.run_command(\"r.colors\", map=\"drainage\", color=\"aspect\")\n", "\n", @@ -193,13 +215,19 @@ "outputs": [], "source": [ "# Count cells in each watershed\n", - "gs.run_command(\"r.stats.zonal\", base=\"watersheds\", cover=\"elevation\", method=\"count\", output=\"watersheds_count\")\n", + "gs.run_command(\n", + " \"r.stats.zonal\",\n", + " base=\"watersheds\",\n", + " cover=\"elevation\",\n", + " method=\"count\",\n", + " output=\"watersheds_count\",\n", + ")\n", "\n", "# Get projection resolution\n", - "proj=gs.parse_command(\"g.region\", flags=\"m\")\n", + "proj = gs.parse_command(\"g.region\", flags=\"m\")\n", "\n", "# Multiply N-S resollution by E-W resolution to get cell area\n", - "cell_area = float(proj[\"nsres\"])*float(proj[\"ewres\"])\n", + "cell_area = float(proj[\"nsres\"]) * float(proj[\"ewres\"])\n", "\n", "# Calculate watersheds areas and convert from m2 to km2\n", "gs.mapcalc(\"'watershed_area' = float('watersheds_count'*{})/1000000\".format(cell_area))" @@ -220,18 +248,20 @@ "source": [ "# Display a map of watershed areas.\n", "gs.run_command(\"r.colors\", map=\"watershed_area\", color=\"plasma\")\n", - " \n", + "\n", "watershed_map = gj.Map()\n", "watershed_map.d_rast(map=\"watershed_area\")\n", - "watershed_map.d_legend(raster=\"watershed_area\",\n", - " bgcolor=\"none\",\n", - " color=\"black\",\n", - " border_color=\"none\",\n", - " at=(3, 40, 84, 88),\n", - " lines=2,\n", - " fontsize=15,\n", - " title=\"Area\",\n", - " units=\" km2\")\n", + "watershed_map.d_legend(\n", + " raster=\"watershed_area\",\n", + " bgcolor=\"none\",\n", + " color=\"black\",\n", + " border_color=\"none\",\n", + " at=(3, 40, 84, 88),\n", + " lines=2,\n", + " fontsize=15,\n", + " title=\"Area\",\n", + " units=\" km2\",\n", + ")\n", "watershed_map.show()" ] }, @@ -265,7 +295,14 @@ "# Display slope map\n", "slope_map = gj.Map()\n", "slope_map.d_rast(map=\"slope\")\n", - "slope_map.d_legend(raster=\"slope\", at=(65, 90, 85, 90), fontsize=15, flags=\"b\", title=\"Slope\", units=\"°\")\n", + "slope_map.d_legend(\n", + " raster=\"slope\",\n", + " at=(65, 90, 85, 90),\n", + " fontsize=15,\n", + " flags=\"b\",\n", + " title=\"Slope\",\n", + " units=\"°\",\n", + ")\n", "slope_map.show()" ] }, @@ -284,14 +321,16 @@ "source": [ "separator = \"|\"\n", "\n", - "columns = defaultdict(list) # each value in each column is appended to a list\n", + "columns = defaultdict(list) # each value in each column is appended to a list\n", "\n", - "text = gs.read_command(\"r.univar\", map=\"elevation\", zones=\"watersheds\", separator=separator, flags=\"t\")\n", + "text = gs.read_command(\n", + " \"r.univar\", map=\"elevation\", zones=\"watersheds\", separator=separator, flags=\"t\"\n", + ")\n", "reader = csv.DictReader(text.splitlines(), delimiter=separator)\n", - "for row in reader: # read a row as {column1: value1, column2: value2,...}\n", - " for (k,v) in row.items(): # go over each column name and value \n", - " columns[k].append(v) # append the value into the appropriate list\n", - " # based on column name k\n", + "for row in reader: # read a row as {column1: value1, column2: value2,...}\n", + " for k, v in row.items(): # go over each column name and value\n", + " columns[k].append(v) # append the value into the appropriate list\n", + " # based on column name k\n", "\n", "watersheds = columns[\"zone\"]\n", "means = np.array(columns[\"mean\"], dtype=np.float32)\n", @@ -333,7 +372,9 @@ "outputs": [], "source": [ "# Convert to vector\n", - "gs.run_command(\"r.to.vect\", flags=\"s\", input=\"watersheds\", output=\"watersheds_vector\", type=\"area\")" + "gs.run_command(\n", + " \"r.to.vect\", flags=\"s\", input=\"watersheds\", output=\"watersheds_vector\", type=\"area\"\n", + ")" ] }, { @@ -345,14 +386,16 @@ "# Display\n", "watershed_vect_map = gj.Map()\n", "watershed_vect_map.d_rast(map=\"elevation\")\n", - "watershed_vect_map.d_vect(map=\"watersheds_vector\",\n", - " fill_color=\"none\",\n", - " width=1.5,\n", - " color=\"black\",\n", - " attribute_column=\"value\",\n", - " label_bgcolor=\"black\",\n", - " label_color=\"white\",\n", - " label_size=10)\n", + "watershed_vect_map.d_vect(\n", + " map=\"watersheds_vector\",\n", + " fill_color=\"none\",\n", + " width=1.5,\n", + " color=\"black\",\n", + " attribute_column=\"value\",\n", + " label_bgcolor=\"black\",\n", + " label_color=\"white\",\n", + " label_size=10,\n", + ")\n", "watershed_vect_map.show()" ] } diff --git a/doc/notebooks/jupyter_example.ipynb b/doc/notebooks/jupyter_example.ipynb index a0f660b5cd3..67245172461 100644 --- a/doc/notebooks/jupyter_example.ipynb +++ b/doc/notebooks/jupyter_example.ipynb @@ -8,7 +8,7 @@ "\n", "[\"GRASS](https://grass.osgeo.org/)\n", "\n", - "This is a quick introduction to *GRASS GIS* in a *Jupyter Notebook* using the [_grass.jupyter_](https://grass.osgeo.org/grass82/manuals/libpython/grass.jupyter.html) package and the *Python* scripting language. The _grass.jupyter_ package simplifies the launch of *GRASS GIS* in *Jupyter Notebook* and provides several useful classes for creating, displaying, and saving *GRASS GIS* maps.\n", + "This is a quick introduction to *GRASS GIS* in a *Jupyter Notebook* using the [_grass.jupyter_](https://grass.osgeo.org/grass-stable/manuals/libpython/grass.jupyter.html) package and the *Python* scripting language. The _grass.jupyter_ package simplifies the launch of *GRASS GIS* in *Jupyter Notebook* and provides several useful classes for creating, displaying, and saving *GRASS GIS* maps.\n", "\n", "The _grass.jupyter_ package was initially written as part of Google Summer of Code in 2021 by Caitlin Haedrich and was experimentally included in version 8.0.0. Caitlin further improved it thanks to the GRASS Mini Grant 2022. The package was officially released for the first time as part of version 8.2.0. If you are curious about how the package improves the integration of *GRASS GIS* and *Jupyter Notebooks*, compare it with [scripting_example.ipynb](scripting_example.ipynb). More features of the _grass.jupyter_ package are presented in [jupyter_tutorial.ipynb](jupyter_tutorial.ipynb).\n", "\n", @@ -64,7 +64,9 @@ "outputs": [], "source": [ "gs.parse_command(\"g.region\", raster=\"lakes\", flags=\"pg\")\n", - "gs.run_command(\"r.buffer\", input=\"lakes\", output=\"lakes_buff\", distances=[60, 120, 240, 500])\n", + "gs.run_command(\n", + " \"r.buffer\", input=\"lakes\", output=\"lakes_buff\", distances=[60, 120, 240, 500]\n", + ")\n", "\n", "# Start a Map\n", "r_buffer_map = gj.Map()\n", @@ -101,7 +103,9 @@ "v_buffer_map = gj.Map()\n", "\n", "# Add vector layers and legend\n", - "v_buffer_map.d_vect(map=\"boundary_state\", fill_color=\"#5A91ED\", legend_label=\"State boundary\")\n", + "v_buffer_map.d_vect(\n", + " map=\"boundary_state\", fill_color=\"#5A91ED\", legend_label=\"State boundary\"\n", + ")\n", "v_buffer_map.d_vect(map=\"buffer\", fill_color=\"#F8766D\", legend_label=\"Inner portion\")\n", "v_buffer_map.d_legend_vect(at=(10, 35))\n", "\n", diff --git a/doc/notebooks/jupyter_tutorial.ipynb b/doc/notebooks/jupyter_tutorial.ipynb index 8213ea970ca..339b78597a3 100644 --- a/doc/notebooks/jupyter_tutorial.ipynb +++ b/doc/notebooks/jupyter_tutorial.ipynb @@ -6,7 +6,7 @@ "source": [ "# The grass.jupyter Package\n", "\n", - "This notebook introduces the [_grass.jupyter_](https://grass.osgeo.org/grass82/manuals/libpython/grass.jupyter.html) package which simplifies the usage of *GRASS GIS* in *Jupyter Notebook*.\n", + "This notebook introduces the [_grass.jupyter_](https://grass.osgeo.org/grass-stable/manuals/libpython/grass.jupyter.html) package which simplifies the usage of *GRASS GIS* in *Jupyter Notebook*.\n", "\n", "The _grass.jupyter_ package was initially written as part of [Google Summer of Code in 2021](https://trac.osgeo.org/grass/wiki/GSoC/2021/JupyterAndGRASS) by Caitlin Haedrich and was experimentally included in version 8.0.0. Caitlin further improved it thanks to the [GRASS Mini Grant 2022](https://trac.osgeo.org/grass/wiki/GSoC/2021/JupyterAndGRASS/MiniGrant2022). The package was officially released for the first time as part of version 8.2.0. Credits for mentoring and additional development go to Vaclav Petras, Helena Mitasova, Stefan Blumentrath, and Anna Petrasova as well as to many members of the GRASS community who provided important feedback.\n", "\n", @@ -142,7 +142,7 @@ "source": [ "# Then, we return to the first instance and continue to modify and display it\n", "# Notice that layers a drawn in the order they are added\n", - "example_map.run(\"d.vect\", map = \"zipcodes\", color=\"red\", fill_color=\"none\")\n", + "example_map.run(\"d.vect\", map=\"zipcodes\", color=\"red\", fill_color=\"none\")\n", "example_map.show()" ] }, @@ -277,11 +277,11 @@ "metadata": {}, "outputs": [], "source": [ - "import folium \n", + "import folium\n", "\n", "\n", "# Create a map\n", - "m = folium.Map(location=[35.761168,-78.668271], zoom_start=13)\n", + "m = folium.Map(location=[35.761168, -78.668271], zoom_start=13)\n", "\n", "# Create and add elevation layer to map\n", "gj.Raster(\"elevation\", opacity=0.5).add_to(m)\n", @@ -291,7 +291,7 @@ "tooltip = \"Click me!\"\n", "# and add a marker\n", "folium.Marker(\n", - " [35.781608,-78.675800], popup=\"Point of Interest\", tooltip=tooltip\n", + " [35.781608, -78.675800], popup=\"Point of Interest\", tooltip=tooltip\n", ").add_to(m)\n", "\n", "# Display map\n", @@ -313,10 +313,10 @@ "metadata": {}, "outputs": [], "source": [ - "import ipyleaflet \n", + "import ipyleaflet\n", "\n", "# Create map\n", - "m = ipyleaflet.Map(center=[35.761168,-78.668271], zoom=13)\n", + "m = ipyleaflet.Map(center=[35.761168, -78.668271], zoom=13)\n", "\n", "# Create and add elevation layer to map\n", "gj.Raster(\"elevation\", opacity=0.5).add_to(m)\n", @@ -325,12 +325,12 @@ "# Like make a tooltip\n", "title = \"Click me!\"\n", "# and add a marker\n", - "marker = ipyleaflet.Marker(name='marker', location=(35.781608,-78.675800), title=title)\n", + "marker = ipyleaflet.Marker(name=\"marker\", location=(35.781608, -78.675800), title=title)\n", "\n", "# Add the marker to the map\n", "m.add(marker)\n", "\n", - "control = ipyleaflet.LayersControl(position='topright')\n", + "control = ipyleaflet.LayersControl(position=\"topright\")\n", "m.add(control)\n", "m" ] @@ -451,9 +451,9 @@ "metadata": {}, "outputs": [], "source": [ - "series = gj.SeriesMap(height = 500)\n", + "series = gj.SeriesMap(height=500)\n", "series.add_rasters([\"elevation\", \"elevation_shade\", \"slope\"])\n", - "#series.add_vectors([\"streams\", \"streets\", \"viewpoints\"])\n", + "# series.add_vectors([\"streams\", \"streets\", \"viewpoints\"])\n", "series.d_vect(map=\"streets\")\n", "series.d_barscale()\n", "series.show() # Create Slider" diff --git a/doc/notebooks/parallelization_tutorial.ipynb b/doc/notebooks/parallelization_tutorial.ipynb index 35a49fa2766..2c5d902e9a4 100644 --- a/doc/notebooks/parallelization_tutorial.ipynb +++ b/doc/notebooks/parallelization_tutorial.ipynb @@ -139,6 +139,7 @@ "import time\n", "from grass.pygrass.modules.grid import GridModule\n", "import time\n", + "\n", "start = time.time()\n", "grid = GridModule(\n", " \"v.surf.idw\",\n", diff --git a/doc/notebooks/scripting_example.ipynb b/doc/notebooks/scripting_example.ipynb index 612904da115..f71ebb8f284 100644 --- a/doc/notebooks/scripting_example.ipynb +++ b/doc/notebooks/scripting_example.ipynb @@ -74,7 +74,9 @@ "outputs": [], "source": [ "gs.parse_command(\"g.region\", raster=\"lakes\", flags=\"pg\")\n", - "gs.run_command(\"r.buffer\", input=\"lakes\", output=\"lakes_buff\", distances=[60, 120, 240, 500])\n", + "gs.run_command(\n", + " \"r.buffer\", input=\"lakes\", output=\"lakes_buff\", distances=[60, 120, 240, 500]\n", + ")\n", "gs.run_command(\"d.erase\")\n", "gs.run_command(\"d.rast\", map=\"lakes_buff\")\n", "gs.run_command(\"d.legend\", raster=\"lakes_buff\", range=(2, 5), at=(80, 100, 2, 10))\n", @@ -102,8 +104,12 @@ "gs.parse_command(\"g.region\", vector=\"boundary_state\", flags=\"pg\")\n", "gs.run_command(\"d.erase\") # erase the display before drawing again\n", "!rm -f $GRASS_LEGEND_FILE # and remove the legend file\n", - "gs.run_command(\"d.vect\", map=\"boundary_state\", fill_color=\"#5A91ED\", legend_label=\"State boundary\")\n", - "gs.run_command(\"d.vect\", map=\"buffer\", fill_color=\"#F8766D\", legend_label=\"Inner portion\")\n", + "gs.run_command(\n", + " \"d.vect\", map=\"boundary_state\", fill_color=\"#5A91ED\", legend_label=\"State boundary\"\n", + ")\n", + "gs.run_command(\n", + " \"d.vect\", map=\"buffer\", fill_color=\"#F8766D\", legend_label=\"Inner portion\"\n", + ")\n", "gs.run_command(\"d.legend.vect\", at=(10, 35))\n", "Image(filename=\"map.png\")" ] diff --git a/doc/notebooks/solar_potential.ipynb b/doc/notebooks/solar_potential.ipynb index cb3fd985910..98253ad6450 100644 --- a/doc/notebooks/solar_potential.ipynb +++ b/doc/notebooks/solar_potential.ipynb @@ -93,7 +93,18 @@ "metadata": {}, "outputs": [], "source": [ - "gs.run_command(\"r.sunmask\", elevation=\"elevation\", year=\"2001\", month=\"12\", day=\"22\", hour=\"16\", minute=\"15\", sec=\"0\", timezone=\"-5\", flags=\"s\")" + "gs.run_command(\n", + " \"r.sunmask\",\n", + " elevation=\"elevation\",\n", + " year=\"2001\",\n", + " month=\"12\",\n", + " day=\"22\",\n", + " hour=\"16\",\n", + " minute=\"15\",\n", + " sec=\"0\",\n", + " timezone=\"-5\",\n", + " flags=\"s\",\n", + ")" ] }, { @@ -111,7 +122,15 @@ "metadata": {}, "outputs": [], "source": [ - "gs.run_command(\"r.sun\", elevation=\"elevation\", aspect=\"aspect\", slope=\"slope\", incidout=\"incident\", day=\"356\", time=\"16.25\")\n", + "gs.run_command(\n", + " \"r.sun\",\n", + " elevation=\"elevation\",\n", + " aspect=\"aspect\",\n", + " slope=\"slope\",\n", + " incidout=\"incident\",\n", + " day=\"356\",\n", + " time=\"16.25\",\n", + ")\n", "gs.parse_command(\"r.info\", map=\"incident\", flags=\"g\")\n", "gs.run_command(\"r.colors\", map=\"incident\", co=\"bcyr\", flags=\"e\")" ] @@ -181,10 +200,26 @@ "metadata": {}, "outputs": [], "source": [ - "gs.run_command(\"r.sun\", elevation=\"elevation\", aspect=\"aspect\", slope=\"slope\", day=\"356\", glob_rad=\"winter\", insol_time=\"its356\")\n", + "gs.run_command(\n", + " \"r.sun\",\n", + " elevation=\"elevation\",\n", + " aspect=\"aspect\",\n", + " slope=\"slope\",\n", + " day=\"356\",\n", + " glob_rad=\"winter\",\n", + " insol_time=\"its356\",\n", + ")\n", "gs.run_command(\"r.colors\", map=\"winter\", co=\"gyr\", flags=\"e\")\n", "\n", - "gs.run_command(\"r.sun\", elevation=\"elevation\", aspect=\"aspect\", slope=\"slope\", day=\"172\", glob_rad=\"summer\", insol_time=\"its172\")\n", + "gs.run_command(\n", + " \"r.sun\",\n", + " elevation=\"elevation\",\n", + " aspect=\"aspect\",\n", + " slope=\"slope\",\n", + " day=\"172\",\n", + " glob_rad=\"summer\",\n", + " insol_time=\"its172\",\n", + ")\n", "gs.run_command(\"r.colors\", map=\"summer\", co=\"gyr\", flags=\"e\")" ] }, diff --git a/doc/notebooks/temporal.ipynb b/doc/notebooks/temporal.ipynb index 9a4433dc7fa..07e030a372c 100644 --- a/doc/notebooks/temporal.ipynb +++ b/doc/notebooks/temporal.ipynb @@ -32,7 +32,9 @@ "!curl http://fatra.cnr.ncsu.edu/temporal-grass-workshop/NC_spm_temporal_workshop.zip -o ../../data/NC_spm_temporal_workshop.zip\n", "\n", "# Unpack zip to grassdata\n", - "shutil.unpack_archive(\"../../data/NC_spm_temporal_workshop.zip\", \"../../data/grassdata\", \"zip\")" + "shutil.unpack_archive(\n", + " \"../../data/NC_spm_temporal_workshop.zip\", \"../../data/grassdata\", \"zip\"\n", + ")" ] }, { @@ -219,7 +221,7 @@ "source": [ "precip_map = gj.TimeSeriesMap(use_region=True)\n", "precip_map.add_raster_series(\"precip_sum_2010\")\n", - "precip_map.d_legend(color=\"black\", at=(10,40,2,6)) #Add legend\n", + "precip_map.d_legend(color=\"black\", at=(10, 40, 2, 6)) # Add legend\n", "precip_map.d_vect(map=\"boundary_county\", fill_color=\"none\")\n", "precip_map.d_barscale()\n", "precip_map.show()" @@ -240,7 +242,11 @@ "source": [ "from IPython.display import Image\n", "\n", - "Image(precip_map.save(\"image.gif\", duration=500, label=True, text_size=16, text_color=\"gray\"))" + "Image(\n", + " precip_map.save(\n", + " \"image.gif\", duration=500, label=True, text_size=16, text_color=\"gray\"\n", + " )\n", + ")" ] }, { diff --git a/doc/notebooks/viewshed_analysis.ipynb b/doc/notebooks/viewshed_analysis.ipynb index 263931ba25c..a4f0b61744a 100644 --- a/doc/notebooks/viewshed_analysis.ipynb +++ b/doc/notebooks/viewshed_analysis.ipynb @@ -65,8 +65,17 @@ "outputs": [], "source": [ "gs.parse_command(\"g.region\", raster=\"elevation\", flags=\"apg\")\n", - "gs.write_command(\"v.in.ascii\", input=\"-\", stdin=\"%s|%s\" % (642212, 224767), output=\"viewpoints\")\n", - "gs.run_command(\"r.viewshed\", input=\"elevation\", output=\"tower_los\", coordinates=\"642212,224767\", observer_elevation=\"165\", max_distance=\"10000\")" + "gs.write_command(\n", + " \"v.in.ascii\", input=\"-\", stdin=\"%s|%s\" % (642212, 224767), output=\"viewpoints\"\n", + ")\n", + "gs.run_command(\n", + " \"r.viewshed\",\n", + " input=\"elevation\",\n", + " output=\"tower_los\",\n", + " coordinates=\"642212,224767\",\n", + " observer_elevation=\"165\",\n", + " max_distance=\"10000\",\n", + ")" ] }, { diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile index 776b8c5a1d4..c15299386cd 100644 --- a/docker/debian/Dockerfile +++ b/docker/debian/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:stable@sha256:fef26aa981ff8c3eeb09b20555ec6e02b38e6b227ec0b88bef7fde778cbf848a +FROM debian:stable@sha256:84725fb1debbf461f54a23030be0bcde8449f2fa4eba8adf857b1a4c707fec8d # currently Debian 12 # docker run -it --rm debian:stable bash diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index cefa32d0656..c45d5796bfe 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -5,7 +5,7 @@ ARG GUI=without -FROM ubuntu:22.04@sha256:1b8d8ff4777f36f19bfe73ee4df61e3a0b789caeff29caa019539ec7c9a57f95 as common_start +FROM ubuntu:22.04@sha256:a6d2b38300ce017add71440577d5b0a90460d0e57fd7aec21dd0d1b0761bbfb2 as common_start LABEL authors="Carmen Tawalika,Markus Neteler,Anika Weinmann,Stefan Blumentrath" LABEL maintainer="tawalika@mundialis.de,neteler@mundialis.de,weinmann@mundialis.de" diff --git a/docker/ubuntu_wxgui/Dockerfile b/docker/ubuntu_wxgui/Dockerfile index 6a836df4796..21effd03aec 100644 --- a/docker/ubuntu_wxgui/Dockerfile +++ b/docker/ubuntu_wxgui/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04@sha256:1b8d8ff4777f36f19bfe73ee4df61e3a0b789caeff29caa019539ec7c9a57f95 +FROM ubuntu:22.04@sha256:a6d2b38300ce017add71440577d5b0a90460d0e57fd7aec21dd0d1b0761bbfb2 LABEL authors="Carmen Tawalika,Markus Neteler,Anika Weinmann,Tomas Zigo" LABEL maintainer="tawalika@mundialis.de,neteler@mundialis.de,weinmann@mundialis.de" diff --git a/general/CMakeLists.txt b/general/CMakeLists.txt new file mode 100644 index 00000000000..4a7afaf4fe6 --- /dev/null +++ b/general/CMakeLists.txt @@ -0,0 +1,65 @@ +build_program_in_subdir(g.access DEPENDS grass_gis) +build_program_in_subdir(g.copy DEPENDS grass_manage) +build_program_in_subdir(g.dirseps DEPENDS grass_gis) +build_program_in_subdir(g.filename DEPENDS grass_gis) +build_program_in_subdir(g.findetc DEPENDS grass_gis) +build_program_in_subdir(g.findfile DEPENDS grass_manage) +build_program_in_subdir(g.gisenv DEPENDS grass_gis) +build_program_in_subdir(g.mapset DEPENDS grass_gis) +build_program_in_subdir(g.mapsets DEPENDS grass_gis grass_parson) +build_program_in_subdir(g.message DEPENDS grass_gis) +build_program_in_subdir(g.mkfontcap DEPENDS grass_gis FREETYPE) +add_dependencies(g.mkfontcap fonts) +add_custom_command( + TARGET g.mkfontcap + POST_BUILD + COMMAND ${grass_env_command} ${GISBASE}/bin/g.mkfontcap -o) +build_program_in_subdir(g.parser DEPENDS grass_gis FREETYPE) +build_program_in_subdir(g.pnmcomp DEPENDS grass_gis) +if(WITH_LIBPNG) + build_program_in_subdir(g.ppmtopng DEPENDS grass_gis LIBPNG) +endif() +build_program_in_subdir(g.proj DEPENDS grass_gis grass_gproj GDAL) +build_program_in_subdir( + g.region + DEPENDS + grass_gis + grass_gproj + grass_vector + grass_raster3d + grass_gmath) + +build_program_in_subdir(g.rename DEPENDS grass_manage grass_raster) +build_program_in_subdir(g.tempfile DEPENDS grass_gis) + +build_program_in_subdir( + g.version + DEPENDS + grass_gis + PROJ + GDAL + SQLITE + OPTIONAL_DEPENDS + GEOS + DEFS + "-DGRASS_VERSION_NUMBER=\"${GRASS_VERSION_NUMBER}\"" + "-DGRASS_VERSION_GIT=\"${GRASS_VERSION_GIT}\"" + "-DGRASS_VERSION_UPDATE_PKG=${GRASS_VERSION_UPDATE_PKG}" + "-DARCH=\"${BUILD_ARCH}\"") + +# TODO: add CAIRO_HAS_XRENDER and CAIRO_HAS_XRENDER_SURFACE to if clause +if(WITH_CAIRO AND USE_X11) + if(NOT MSVC) + build_program_in_subdir(g.cairocomp DEPENDS grass_gis CAIRO + grass_cairodriver) + endif() +endif() + +add_subdirectory(manage/lister) + +build_program_in_subdir(g.list DEPENDS grass_manage) +add_dependencies(g.list cell vector) + +build_program_in_subdir(g.remove DEPENDS grass_manage grass_raster) + +build_program_in_subdir(g.gui DEPENDS grass_raster) diff --git a/general/g.mapset/main.c b/general/g.mapset/main.c index dc70b1fbc41..0ebb4379d27 100644 --- a/general/g.mapset/main.c +++ b/general/g.mapset/main.c @@ -50,7 +50,7 @@ int main(int argc, char *argv[]) G_add_keyword(_("settings")); module->label = _("Changes/reports current mapset."); module->description = _("Optionally create new mapset or list available " - "mapsets in given location."); + "mapsets in given project (location)."); opt.mapset = G_define_standard_option(G_OPT_M_MAPSET); opt.mapset->required = YES; diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index 55c8c81f646..d346829722f 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -88,7 +88,7 @@ int main(int argc, char *argv[]) G_add_keyword(_("search path")); module->label = _("Modifies/prints the user's current mapset search path."); module->description = _("Affects the user's access to data existing " - "under the other mapsets in the current location."); + "under the other mapsets in the current project."); opt.mapset = G_define_standard_option(G_OPT_M_MAPSET); opt.mapset->required = YES; diff --git a/general/g.mapsets/tests/conftest.py b/general/g.mapsets/tests/conftest.py index ca58228607c..58986369c03 100644 --- a/general/g.mapsets/tests/conftest.py +++ b/general/g.mapsets/tests/conftest.py @@ -5,7 +5,6 @@ Fixture for ReprojectionRenderer test with simple GRASS location, raster, vector. """ - from types import SimpleNamespace import grass.script as gs @@ -28,7 +27,7 @@ def simple_dataset(tmp_path_factory): gs.run_command("g.region", s=0, n=80, w=0, e=120, b=0, t=50, res=10, res3=10) # Create Mock Mapsets for mapset in TEST_MAPSETS: - gs.run_command("g.mapset", location=location, mapset=mapset, flags="c") + gs.run_command("g.mapset", project=location, mapset=mapset, flags="c") yield SimpleNamespace( mapsets=TEST_MAPSETS, accessible_mapsets=ACCESSIBLE_MAPSETS diff --git a/general/g.mkfontcap/main.c b/general/g.mkfontcap/main.c index 0a4a80fbae6..8122ba158e5 100644 --- a/general/g.mkfontcap/main.c +++ b/general/g.mkfontcap/main.c @@ -5,7 +5,7 @@ * PURPOSE: Generates the font configuration file by scanning various * directories for GRASS stroke and Freetype-compatible fonts. * - * COPYRIGHT: (C) 2007-2015 by the GRASS Development Team + * COPYRIGHT: (C) 2007-2024 by the GRASS Development Team * * This program is free software under the GNU General Public * License (>=v2). Read the file COPYING that comes with GRASS @@ -47,7 +47,7 @@ static int compare_fonts(const void *, const void *); int main(int argc, char *argv[]) { - struct Flag *tostdout, *overwrite; + struct Flag *tostdout; struct Option *extradirs; struct GModule *module; @@ -65,11 +65,6 @@ int main(int argc, char *argv[]) "Generates the font configuration file by scanning various directories " "for fonts."); - overwrite = G_define_flag(); - overwrite->key = 'o'; - overwrite->description = - _("Overwrite font configuration file if already existing"); - tostdout = G_define_flag(); tostdout->key = 's'; tostdout->description = @@ -99,11 +94,11 @@ int main(int argc, char *argv[]) G_asprintf(&fontcapfile, "%s/etc/fontcap", gisbase); if (!access(fontcapfile, F_OK)) { /* File exists? */ - if (!overwrite->answer) - G_fatal_error( - _("Fontcap file %s already exists; use -%c flag if you " - "wish to overwrite it"), - fontcapfile, overwrite->key); + if (!G_get_overwrite()) + G_fatal_error(_("Fontcap file %s already exists; use " + "--overwrite flag if you " + "wish to overwrite it"), + fontcapfile); } } diff --git a/general/g.proj/create.c b/general/g.proj/create.c index 3240c87198b..c2c693f7aa1 100644 --- a/general/g.proj/create.c +++ b/general/g.proj/create.c @@ -13,18 +13,18 @@ void create_location(const char *location) ret = G_make_location_crs(location, &cellhd, projinfo, projunits, projsrid, projwkt); if (ret == 0) - G_message(_("Location <%s> created"), location); + G_message(_("Project <%s> created"), location); else if (ret == -1) - G_fatal_error(_("Unable to create location <%s>: %s"), location, + G_fatal_error(_("Unable to create project <%s>: %s"), location, strerror(errno)); else if (ret == -2) G_fatal_error(_("Unable to create projection files: %s"), strerror(errno)); else /* Shouldn't happen */ - G_fatal_error(_("Unable to create location <%s>"), location); + G_fatal_error(_("Unable to create project <%s>"), location); - G_message(_("You can switch to the new location by\n`%s=%s`"), + G_message(_("You can switch to the new project by\n`%s=%s`"), "g.mapset mapset=PERMANENT project", location); } @@ -36,7 +36,8 @@ void modify_projinfo(void) if (strcmp(mapset, "PERMANENT") != 0) G_fatal_error( _("You must select the PERMANENT mapset before updating the " - "current location's projection (current mapset is <%s>)"), + "current project's coordinate reference system" + " (current mapset is <%s>)"), mapset); /* Read projection information from current location first */ diff --git a/general/g.region/printwindow.c b/general/g.region/printwindow.c index dc2b8b3de55..d35ed167926 100644 --- a/general/g.region/printwindow.c +++ b/general/g.region/printwindow.c @@ -248,15 +248,15 @@ void print_window(struct Cell_head *window, int print_flag, int flat_flag) /* read current projection info */ if ((in_proj_info = G_get_projinfo()) == NULL) G_fatal_error( - _("Can't get projection info of current location")); + _("Can't get projection info of current project")); if ((in_unit_info = G_get_projunits()) == NULL) G_fatal_error( - _("Can't get projection units of current location")); + _("Can't get projection units of current project")); if (pj_get_kv(&iproj, in_proj_info, in_unit_info) < 0) G_fatal_error( - _("Can't get projection key values of current location")); + _("Can't get projection key values of current project")); G_free_key_value(in_proj_info); G_free_key_value(in_unit_info); @@ -399,7 +399,7 @@ void print_window(struct Cell_head *window, int print_flag, int flat_flag) _("You are already in Lat/Long. Use the -p flag instead.")); else G_message( - _("You are in a simple XY location, projection to Lat/Lon " + _("You are in a simple XY project, projection to Lat/Lon " "is not possible. Use the -p flag instead.")); } } @@ -493,15 +493,15 @@ void print_window(struct Cell_head *window, int print_flag, int flat_flag) /* read current projection info */ if ((in_proj_info = G_get_projinfo()) == NULL) G_fatal_error( - _("Can't get projection info of current location")); + _("Can't get projection info of current project")); if ((in_unit_info = G_get_projunits()) == NULL) G_fatal_error( - _("Can't get projection units of current location")); + _("Can't get projection units of current project")); if (pj_get_kv(&iproj, in_proj_info, in_unit_info) < 0) G_fatal_error( - _("Can't get projection key values of current location")); + _("Can't get projection key values of current project")); G_free_key_value(in_proj_info); G_free_key_value(in_unit_info); @@ -567,7 +567,7 @@ void print_window(struct Cell_head *window, int print_flag, int flat_flag) /* read current projection info */ if ((in_proj_info = G_get_projinfo()) == NULL) G_fatal_error( - _("Can't get projection info of current location")); + _("Can't get projection info of current project")); /* do not wrap to -180, 180, otherwise east can be < west */ /* TODO: for PROJ 6+, the +over switch must be added to the * transformation pipeline if authority:name or WKt are used @@ -576,11 +576,11 @@ void print_window(struct Cell_head *window, int print_flag, int flat_flag) if ((in_unit_info = G_get_projunits()) == NULL) G_fatal_error( - _("Can't get projection units of current location")); + _("Can't get projection units of current project")); if (pj_get_kv(&iproj, in_proj_info, in_unit_info) < 0) G_fatal_error( - _("Can't get projection key values of current location")); + _("Can't get projection key values of current project")); /* output projection to lat/long and wgs84 ellipsoid */ out_proj_info = G_create_key_value(); @@ -594,7 +594,7 @@ void print_window(struct Cell_head *window, int print_flag, int flat_flag) /* PROJ6+ has its own datum transformation parameters */ if (G_get_datumparams_from_projinfo(in_proj_info, buff, dum) < 0) G_fatal_error(_( - "WGS84 output not possible as this location does not " + "WGS84 output not possible as this project does not " "contain " "datum transformation parameters. Try running g.setproj.")); else diff --git a/general/g.region/testsuite/test_g_region.py b/general/g.region/testsuite/test_g_region.py index b2f9d8aa83e..7362c062f1d 100644 --- a/general/g.region/testsuite/test_g_region.py +++ b/general/g.region/testsuite/test_g_region.py @@ -2,6 +2,7 @@ @author Anna Petrasova """ + from grass.gunittest.case import TestCase from grass.gunittest.gmodules import call_module import grass.script as gs diff --git a/general/g.version/g.version.html b/general/g.version/g.version.html index 7e1a0bb906f..d72632d932b 100644 --- a/general/g.version/g.version.html +++ b/general/g.version/g.version.html @@ -38,7 +38,7 @@

Basic info

 g.version
 
-GRASS 8.2.0dev (2022)
+GRASS 8.4.0 (2024)
 

GIS Library info

@@ -46,23 +46,23 @@

GIS Library info

 g.version -r
 
-GRASS 8.2.0dev (2022)
+GRASS 8.4.0 (2024)
 libgis revision: c9e8576cf
-libgis date: 2022-04-27T09:38:49+00:00
+libgis date: 2024-04-27T09:38:49+00:00
 

Full info in shell script style

 g.version -rge
 
-version=8.2.0dev
-date=2022
+version=8.4.0
+date=2024
 revision=d57f40906
-build_date=2021-05-23
+build_date=2024-05-23
 build_platform=x86_64-pc-linux-gnu
 build_off_t_size=8
 libgis_revision=c9e8576cf
-libgis_date=2022-04-27T09:38:49+00:00
+libgis_date=2024-04-27T09:38:49+00:00
 proj=8.2.1
 gdal=3.4.3
 geos=3.9.2
diff --git a/general/manage/lister/CMakeLists.txt b/general/manage/lister/CMakeLists.txt
new file mode 100644
index 00000000000..b0ac9a86b19
--- /dev/null
+++ b/general/manage/lister/CMakeLists.txt
@@ -0,0 +1,25 @@
+build_program(
+  NAME
+  cell
+  SOURCES
+  "cell.c"
+  DEPENDS
+  grass_vector
+  grass_dbmibase
+  grass_gis
+  grass_raster
+  RUNTIME_OUTPUT_DIR
+  etc/lister)
+
+build_program(
+  NAME
+  vector
+  SOURCES
+  "vector.c"
+  DEPENDS
+  grass_vector
+  grass_dbmibase
+  grass_gis
+  grass_raster
+  RUNTIME_OUTPUT_DIR
+  etc/lister)
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
new file mode 100644
index 00000000000..815d347c6b9
--- /dev/null
+++ b/gui/CMakeLists.txt
@@ -0,0 +1,9 @@
+
+add_subdirectory(icons)
+add_subdirectory(images)
+
+# add_subdirectory(scripts)
+
+add_subdirectory(wxpython)
+
+install(FILES xml/grass-interface.dtd DESTINATION gui/xml)
diff --git a/gui/icons/CMakeLists.txt b/gui/icons/CMakeLists.txt
new file mode 100644
index 00000000000..33374a88dfd
--- /dev/null
+++ b/gui/icons/CMakeLists.txt
@@ -0,0 +1,76 @@
+file(GLOB GUI_ICONS "*.ico" "*.png")
+file(GLOB GRASS_ICONS "grass/*.png")
+file(GLOB FLAGS_ICONS "flags/*.png")
+
+add_custom_target(
+  make_gui_icons_dirs
+  COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/gui/icons/grass
+  COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/gui/icons/flags
+  COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/docs/html/icons
+  COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/gui/images/symbols)
+
+set(output_icons)
+foreach(ICON ${GUI_ICONS})
+  get_filename_component(FILE_NAME ${ICON} NAME)
+  add_custom_command(
+    OUTPUT ${GISBASE}/gui/icons/${FILE_NAME}
+    COMMAND ${CMAKE_COMMAND} -E copy ${ICON} ${GISBASE}/gui/icons/)
+  list(APPEND output_icons ${GISBASE}/gui/icons/${FILE_NAME})
+endforeach()
+
+foreach(ICON ${GRASS_ICONS})
+  get_filename_component(FILE_NAME ${ICON} NAME)
+  add_custom_command(
+    OUTPUT ${GISBASE}/gui/icons/grass/${FILE_NAME}
+    COMMAND ${CMAKE_COMMAND} -E copy ${ICON} ${GISBASE}/gui/icons/grass/)
+  list(APPEND output_icons ${GISBASE}/gui/icons/grass/${FILE_NAME})
+
+  add_custom_command(
+    OUTPUT ${GISBASE}/docs/html/icons/${FILE_NAME}
+    COMMAND ${CMAKE_COMMAND} -E copy ${ICON} ${GISBASE}/docs/html/icons/)
+  list(APPEND output_icons ${GISBASE}/docs/html/icons/${FILE_NAME})
+endforeach()
+
+foreach(ICON ${FLAGS_ICONS})
+  get_filename_component(FILE_NAME ${ICON} NAME)
+  add_custom_command(
+    OUTPUT ${GISBASE}/gui/icons/flags/${FILE_NAME}
+    COMMAND ${CMAKE_COMMAND} -E copy ${ICON} ${GISBASE}/gui/icons/flags/)
+  list(APPEND output_icons ${GISBASE}/gui/icons/flags/${FILE_NAME})
+endforeach()
+
+add_custom_target(gui_icons DEPENDS make_gui_icons_dirs ${output_icons})
+
+install(FILES ${GUI_ICONS} DESTINATION gui/icons)
+install(FILES ${GRASS_ICONS} DESTINATION gui/icons/grass)
+install(FILES ${FLAGS_ICONS} DESTINATION gui/icons/flags)
+install(FILES ${GRASS_ICONS} DESTINATION docs/html/icons)
+install(FILES grass.desktop DESTINATION share/applications)
+foreach(
+  icon_type
+  8
+  16
+  22
+  24
+  32
+  36
+  40
+  42
+  48
+  64
+  72
+  80
+  96
+  128
+  192)
+  set(icon_size "${icon_type}x${icon_type}")
+  install(FILES grass-${icon_size}.png
+          DESTINATION share/icons/hicolor/${icon_size}/apps)
+endforeach()
+
+install(
+  FILES grass.svg
+  DESTINATION share/icons/hicolor/scalable/apps
+  RENAME grass${GRASS_VERSION_MAJOR}${GRASS_VERSION_MINOR}.svg)
+
+install(FILES grass.appdata.xml DESTINATION share/appdata)
diff --git a/gui/images/CMakeLists.txt b/gui/images/CMakeLists.txt
new file mode 100644
index 00000000000..72dcce79f84
--- /dev/null
+++ b/gui/images/CMakeLists.txt
@@ -0,0 +1,31 @@
+file(GLOB GUI_IMAGES "*.png")
+
+set(output_images)
+foreach(IMG ${GUI_IMAGES})
+  get_filename_component(FILE_NAME ${IMG} NAME)
+  add_custom_command(
+    OUTPUT ${GISBASE}/gui/images/${FILE_NAME}
+    COMMAND ${CMAKE_COMMAND} -E copy ${IMG} ${GISBASE}/gui/images/)
+  list(APPEND output_images ${GISBASE}/gui/images/${FILE_NAME})
+endforeach()
+
+if(CMAKE_VERSION VERSION_LESS 3.17)
+  set(RM remove)
+else()
+  set(RM rm)
+endif()
+
+add_custom_target(
+  gui_images
+  COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/symbols
+          ${GISBASE}/gui/images/symbols
+  COMMAND ${CMAKE_COMMAND} -E ${RM}  ${GISBASE}/gui/images/symbols/README
+  DEPENDS gui_icons ${output_images})
+
+install(FILES ${GUI_IMAGES} DESTINATION gui/images/)
+install(DIRECTORY symbols/basic DESTINATION gui/images/symbols/)
+install(DIRECTORY symbols/demo DESTINATION gui/images/symbols/)
+install(DIRECTORY symbols/extra DESTINATION gui/images/symbols/)
+install(DIRECTORY symbols/geology DESTINATION gui/images/symbols/)
+install(DIRECTORY symbols/legend DESTINATION gui/images/symbols/)
+install(DIRECTORY symbols/n_arrows DESTINATION gui/images/symbols/)
diff --git a/gui/wxpython/CMakeLists.txt b/gui/wxpython/CMakeLists.txt
new file mode 100644
index 00000000000..6d10450b2c9
--- /dev/null
+++ b/gui/wxpython/CMakeLists.txt
@@ -0,0 +1,132 @@
+# missing docs
+
+set(WXPYTHON_DIR ${GISBASE}/gui/wxpython)
+set(gui_lib_DIRS
+    core
+    gui_core
+    history
+    icons
+    iscatt
+    lmgr
+    location_wizard
+    main_window
+    mapdisp
+    mapwin
+    modules
+    nviz
+    rdigit
+    startup
+    tools
+    vnet
+    web_services
+    wxplot)
+
+set(gui_lib_targets)
+foreach(gui_lib_DIR ${gui_lib_DIRS})
+  copy_python_files_in_subdir(${gui_lib_DIR} gui/wxpython)
+  list(APPEND gui_lib_targets python_${gui_lib_DIR})
+endforeach()
+add_custom_target(
+  GUI_WXPYTHON
+  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/wxgui.py
+          ${WXPYTHON_DIR}/
+  DEPENDS ${gui_lib_targets})
+
+set(gui_DIRS
+    animation
+    datacatalog
+    dbmgr
+    gcp
+    gmodeler
+    iclass
+    image2target
+    mapswipe
+    photo2image
+    psmap
+    rlisetup
+    timeline
+    tplot
+    vdigit)
+set(g_gui_targets)
+foreach(gui_DIR ${gui_DIRS})
+  build_gui_in_subdir(${gui_DIR})
+  list(APPEND g_gui_targets "g.gui.${gui_DIR}")
+endforeach()
+
+add_subdirectory(docs)
+
+install(FILES README DESTINATION gui/wxpython)
+
+# copy all python files gui/ lib/python compile all python files so below target
+# depends on MODULD_LIST
+
+add_custom_target(
+  copy_wxpython_xml
+  COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/xml
+          ${WXPYTHON_DIR}/xml/
+  COMMAND ${CMAKE_COMMAND} -E copy
+          ${CMAKE_CURRENT_SOURCE_DIR}/../xml/grass-interface.dtd ${GISBASE}/gui/
+  DEPENDS GUI_WXPYTHON)
+
+add_custom_target(
+  compile_python_files
+  COMMAND ${PYTHON_EXECUTABLE} -m compileall ${GISBASE}/scripts
+  COMMAND ${PYTHON_EXECUTABLE} -m compileall ${WXPYTHON_DIR}
+  DEPENDS ALL_MODULES)
+
+add_custom_target(
+  build_modules_items_xml
+  COMMAND
+    ${grass_env_command} ${PYTHON_EXECUTABLE}
+    ${CMAKE_CURRENT_SOURCE_DIR}/tools/build_modules_xml.py >
+    ${WXPYTHON_DIR}/xml/module_items.xml
+  DEPENDS copy_wxpython_xml compile_python_files ${g_gui_targets}
+  COMMENT "Generating interface description for all modules..."
+  VERBATIM)
+
+add_custom_target(
+  build_xml_menudata
+  COMMAND
+    ${grass_env_command} ${PYTHON_EXECUTABLE}
+    ${CMAKE_CURRENT_SOURCE_DIR}/core/toolboxes.py >
+    ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/menudata.xml
+  COMMAND
+    ${grass_env_command} ${PYTHON_EXECUTABLE}
+    ${CMAKE_CURRENT_SOURCE_DIR}/core/toolboxes.py "validate"
+    ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/menudata.xml
+  COMMAND
+    ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/menudata.xml
+    ${WXPYTHON_DIR}/xml/
+  DEPENDS build_modules_items_xml)
+
+add_custom_target(
+  build_module_tree_menudata
+  COMMAND
+    ${grass_env_command} ${PYTHON_EXECUTABLE}
+    ${CMAKE_CURRENT_SOURCE_DIR}/core/toolboxes.py "module_tree" >
+    ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/module_tree_menudata.xml
+  COMMAND
+    ${grass_env_command} ${PYTHON_EXECUTABLE}
+    ${CMAKE_CURRENT_SOURCE_DIR}/core/toolboxes.py "validate"
+    ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/module_tree_menudata.xml
+  COMMAND
+    ${CMAKE_COMMAND} -E copy
+    ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/module_tree_menudata.xml
+    ${WXPYTHON_DIR}/xml/
+  DEPENDS build_xml_menudata)
+
+add_custom_target(
+  build_menustrings ALL
+  COMMAND
+    ${grass_env_command} ${PYTHON_EXECUTABLE}
+    ${CMAKE_CURRENT_SOURCE_DIR}/core/menutree.py "manager" >>
+    ${CMAKE_CURRENT_SOURCE_DIR}/menustrings.py
+  COMMAND
+    ${grass_env_command} ${PYTHON_EXECUTABLE}
+    ${CMAKE_CURRENT_SOURCE_DIR}/core/menutree.py "module_tree" >>
+    ${CMAKE_CURRENT_SOURCE_DIR}/menustrings.py
+  COMMAND
+    ${grass_env_command} ${PYTHON_EXECUTABLE}
+    ${CMAKE_CURRENT_SOURCE_DIR}/core/menutree.py "psmap" >>
+    ${CMAKE_CURRENT_SOURCE_DIR}/menustrings.py
+  DEPENDS build_module_tree_menudata gui_images)
diff --git a/gui/wxpython/animation/controller.py b/gui/wxpython/animation/controller.py
index d6488d53263..ed03f7dadb5 100644
--- a/gui/wxpython/animation/controller.py
+++ b/gui/wxpython/animation/controller.py
@@ -13,6 +13,7 @@
 
 @author Anna Petrasova 
 """
+
 import os
 import wx
 
diff --git a/gui/wxpython/animation/data.py b/gui/wxpython/animation/data.py
index d19c2d21054..5c2cdf35ef1 100644
--- a/gui/wxpython/animation/data.py
+++ b/gui/wxpython/animation/data.py
@@ -15,6 +15,7 @@
 
 @author Anna Petrasova 
 """
+
 import os
 import copy
 
diff --git a/gui/wxpython/animation/frame.py b/gui/wxpython/animation/frame.py
index 38f07866264..e5bbd389d4c 100644
--- a/gui/wxpython/animation/frame.py
+++ b/gui/wxpython/animation/frame.py
@@ -17,6 +17,7 @@
 
 @author Anna Petrasova 
 """
+
 import os
 import wx
 import wx.aui
diff --git a/gui/wxpython/animation/provider.py b/gui/wxpython/animation/provider.py
index 10d83ec02f5..c23cede79ef 100644
--- a/gui/wxpython/animation/provider.py
+++ b/gui/wxpython/animation/provider.py
@@ -19,6 +19,7 @@
 
 @author Anna Petrasova 
 """
+
 import os
 import sys
 import wx
@@ -92,9 +93,9 @@ def SetCmds(self, cmdsForComposition, opacities, regions=None):
         Applies to 2D mode.
 
         :param cmdsForComposition: list of lists of command lists
-                                   [[['d.rast', 'map=elev_2001'], ['d.vect', 'map=points']], # g.pnmcomp
-                                   [['d.rast', 'map=elev_2002'], ['d.vect', 'map=points']],
-                                   ...]
+                   [[['d.rast', 'map=elev_2001'], ['d.vect', 'map=points']], # g.pnmcomp
+                   [['d.rast', 'map=elev_2002'], ['d.vect', 'map=points']],
+                   ...]
         :param opacities: list of opacity values
         :param regions: list of regions
         """
@@ -427,9 +428,9 @@ def Render(self, cmdList, regions, regionFor3D, bgcolor, force, nprocs):
                 for i in range(len(cmd_list)):
                     proc_list[i].join()
                     filename = queue_list[i].get()
-                    self._mapFilesPool[
-                        HashCmd(cmd_list[i][0], cmd_list[i][1])
-                    ] = filename
+                    self._mapFilesPool[HashCmd(cmd_list[i][0], cmd_list[i][1])] = (
+                        filename
+                    )
                     self._mapFilesPool.SetSize(
                         HashCmd(cmd_list[i][0], cmd_list[i][1]),
                         (self.imageWidth, self.imageHeight),
@@ -540,15 +541,17 @@ def Compose(self, cmdLists, regions, opacityList, bgcolor, force, nprocs):
                     proc_list[i].join()
                     filename = queue_list[i].get()
                     if filename is None:
-                        self._bitmapPool[
-                            HashCmds(cmd_lists[i][0], cmd_lists[i][1])
-                        ] = createNoDataBitmap(
-                            self.imageWidth, self.imageHeight, text="Failed to render"
+                        self._bitmapPool[HashCmds(cmd_lists[i][0], cmd_lists[i][1])] = (
+                            createNoDataBitmap(
+                                self.imageWidth,
+                                self.imageHeight,
+                                text="Failed to render",
+                            )
                         )
                     else:
-                        self._bitmapPool[
-                            HashCmds(cmd_lists[i][0], cmd_lists[i][1])
-                        ] = BitmapFromImage(wx.Image(filename))
+                        self._bitmapPool[HashCmds(cmd_lists[i][0], cmd_lists[i][1])] = (
+                            BitmapFromImage(wx.Image(filename))
+                        )
                         os.remove(filename)
                 proc_count = 0
                 proc_list = []
diff --git a/gui/wxpython/animation/temporal_manager.py b/gui/wxpython/animation/temporal_manager.py
index 4fc31f75d26..e5ee593415a 100644
--- a/gui/wxpython/animation/temporal_manager.py
+++ b/gui/wxpython/animation/temporal_manager.py
@@ -135,7 +135,8 @@ def _setTemporalState(self):
             message = _(
                 "You are going to display data with different "
                 "temporal types of maps (interval and point)."
-                " It is recommended to use data of one temporal type to avoid confusion."
+                " It is recommended to use data of one temporal type to avoid "
+                "confusion."
             )
             return True, message  # warning
 
@@ -221,9 +222,11 @@ def GetLabelsAndMaps(self):
             timestamps = [
                 (
                     datetime.datetime.strftime(st, formatString),
-                    datetime.datetime.strftime(end, formatString)
-                    if end is not None
-                    else None,
+                    (
+                        datetime.datetime.strftime(end, formatString)
+                        if end is not None
+                        else None
+                    ),
                     unit,
                 )
                 for (st, end, unit) in timestamps
diff --git a/gui/wxpython/animation/toolbars.py b/gui/wxpython/animation/toolbars.py
index 0fc21c70366..1ac3c2efedb 100644
--- a/gui/wxpython/animation/toolbars.py
+++ b/gui/wxpython/animation/toolbars.py
@@ -17,6 +17,7 @@
 
 @author Anna Petrasova 
 """
+
 import wx
 from gui_core.toolbars import BaseToolbar, BaseIcons
 from icons.icon import MetaIcon
diff --git a/gui/wxpython/animation/utils.py b/gui/wxpython/animation/utils.py
index b6c0d27abac..9be0fe78c17 100644
--- a/gui/wxpython/animation/utils.py
+++ b/gui/wxpython/animation/utils.py
@@ -17,6 +17,7 @@
 
 @author Anna Perasova 
 """
+
 import os
 import wx
 import hashlib
diff --git a/gui/wxpython/core/debug.py b/gui/wxpython/core/debug.py
index 090cd9c60d3..86bb006d603 100644
--- a/gui/wxpython/core/debug.py
+++ b/gui/wxpython/core/debug.py
@@ -48,8 +48,9 @@ def SetLevel(self):
             self.debuglevel = 0
             sys.stderr.write(
                 _(
-                    "WARNING: Ignoring unsupported wx debug level (must be >=0 and <=5). {0}\n"
-                ).format(e)
+                    "WARNING: Ignoring unsupported wx debug level (must be >=0 and "
+                    "<=5). {0}\n".format(e)
+                )
             )
 
     def msg(self, level, message, *args):
diff --git a/gui/wxpython/core/gcmd.py b/gui/wxpython/core/gcmd.py
index eca7ef05898..138936fb4f5 100644
--- a/gui/wxpython/core/gcmd.py
+++ b/gui/wxpython/core/gcmd.py
@@ -688,7 +688,8 @@ def RunCommand(
     :param env: environment (optional, uses os.environ if not provided)
     :param kwargs: program parameters
 
-    The environment passed to the function (env or os.environ) is not modified (a copy is used internally).
+    The environment passed to the function (env or os.environ) is not modified
+    (a copy is used internally).
 
     :return: returncode (read == False and getErrorMsg == False)
     :return: returncode, messages (read == False and getErrorMsg == True)
diff --git a/gui/wxpython/core/giface.py b/gui/wxpython/core/giface.py
index 8cb430d7650..951c9cb42dd 100644
--- a/gui/wxpython/core/giface.py
+++ b/gui/wxpython/core/giface.py
@@ -218,10 +218,12 @@ def __init__(self):
         # Signal for communicating something in current grassdb has changed.
         # Parameters:
         # action: required, is one of 'new', 'rename', 'delete'
-        # element: required, can be one of 'grassdb', 'location', 'mapset', 'raster', 'vector' and 'raster_3d'
+        # element: required, can be one of 'grassdb', 'location', 'mapset', 'raster',
+        #          'vector' and 'raster_3d'
         # grassdb: path to grass db, required
         # location: location name, required
-        # mapset: mapset name, required when element is 'mapset', 'raster', 'vector' or 'raster_3d'
+        # mapset: mapset name, required when element is 'mapset', 'raster',
+        #         'vector' or 'raster_3d'
         # map: map name, required when element is 'raster', 'vector' or 'raster_3d'
         # newname: new name (of mapset, map), required with action='rename'
         self.grassdbChanged = Signal("StandaloneGrassInterface.grassdbChanged")
diff --git a/gui/wxpython/core/render.py b/gui/wxpython/core/render.py
index 2bab7806bab..6e658252bbd 100644
--- a/gui/wxpython/core/render.py
+++ b/gui/wxpython/core/render.py
@@ -1049,7 +1049,8 @@ def GetRegion(
         :param rast: list of raster maps
         :param zoom: zoom to raster map (ignore NULLs)
         :param vect: list of vector maps
-        :param rast3d: 3d raster map (not list, no support of multiple 3d rasters in g.region)
+        :param rast3d: 3d raster map (not list, no support of multiple 3d rasters in
+                       g.region)
         :param regionName:  named region or None
         :param n,s,e,w: force extent
         :param default: force default region settings
@@ -1256,7 +1257,8 @@ def GetListOfLayers(
         """Returns list of layers of selected properties or list of
         all layers.
 
-        :param ltype: layer type, e.g. raster/vector/wms/overlay (value or tuple of values)
+        :param ltype: layer type, e.g. raster/vector/wms/overlay (value or tuple of
+                      values)
         :param mapset: all layers from given mapset (only for maplayers)
         :param name: all layers with given name
         :param active: only layers with 'active' attribute set to True or False
diff --git a/gui/wxpython/core/settings.py b/gui/wxpython/core/settings.py
index df2d6eebb8e..ea3c2c1c738 100644
--- a/gui/wxpython/core/settings.py
+++ b/gui/wxpython/core/settings.py
@@ -152,6 +152,10 @@ def _defaultSettings(self):
                 "region": {
                     "resAlign": {"enabled": False},
                 },
+                "singleWinPanesLayoutPos": {
+                    "enabled": False,
+                    "pos": "",
+                },
             },
             #
             # datacatalog
diff --git a/gui/wxpython/core/toolboxes.py b/gui/wxpython/core/toolboxes.py
index 8c8c380295c..1d58d59f867 100644
--- a/gui/wxpython/core/toolboxes.py
+++ b/gui/wxpython/core/toolboxes.py
@@ -135,7 +135,10 @@ def getMenudataFile(userRootFile, newFile, fallback):
                 os.remove(menudataFile)
                 _debug(
                     2,
-                    "toolboxes.getMenudataFile: no user defined files, menudata deleted",
+                    (
+                        "toolboxes.getMenudataFile: no user defined files, "
+                        "menudata deleted"
+                    ),
                 )
                 return fallback
 
@@ -144,7 +147,11 @@ def getMenudataFile(userRootFile, newFile, fallback):
                 # any change
                 generateNew = True
                 _debug(
-                    2, "toolboxes.getMenudataFile: only one of the user defined files"
+                    2,
+                    (
+                        "toolboxes.getMenudataFile: only one of the user "
+                        "defined files"
+                    ),
                 )
             else:
                 # if newer files -> generate new
@@ -153,14 +160,20 @@ def getMenudataFile(userRootFile, newFile, fallback):
                     if os.path.getmtime(_getUserToolboxesFile()) > menudataTime:
                         _debug(
                             2,
-                            "toolboxes.getMenudataFile: user toolboxes is newer than menudata",
+                            (
+                                "toolboxes.getMenudataFile: user toolboxes is newer "
+                                "than menudata"
+                            ),
                         )
                         generateNew = True
                 if userRootFile:
                     if os.path.getmtime(userRootFile) > menudataTime:
                         _debug(
                             2,
-                            "toolboxes.getMenudataFile: user root file is newer than menudata",
+                            (
+                                "toolboxes.getMenudataFile: user root file is "
+                                "newer than menudata"
+                            ),
                         )
                         generateNew = True
         elif _getUserToolboxesFile() or userRootFile:
@@ -198,7 +211,10 @@ def getMenudataFile(userRootFile, newFile, fallback):
             except:
                 _debug(
                     2,
-                    "toolboxes.getMenudataFile: writing menudata failed, returning fallback file",
+                    (
+                        "toolboxes.getMenudataFile: writing menudata failed, "
+                        "returning fallback file"
+                    ),
                 )
                 return fallback
         else:
@@ -432,12 +448,16 @@ def _expandUserToolboxesItem(node, toolboxes):
 
     Include all user toolboxes.
 
-    >>> tree = etree.fromstring('')
-    >>> toolboxes = etree.fromstring('')
+    >>> tree = etree.fromstring(
+    ...     ""
+    ... )
+    >>> toolboxes = etree.fromstring(
+    ...     ''
+    ... )
     >>> _expandUserToolboxesItem(tree, toolboxes)
     >>> etree.tostring(tree)
     b''
-    """
+    """  # noqa: E501
     tboxes = toolboxes.findall(".//toolbox")
 
     for n in node.findall("./items/user-toolboxes-list"):
@@ -456,7 +476,9 @@ def _expandUserToolboxesItem(node, toolboxes):
 def _removeUserToolboxesItem(root):
     """Removes tag 'user-toolboxes-list' if there are no user toolboxes.
 
-    >>> tree = etree.fromstring('')
+    >>> tree = etree.fromstring(
+    ...     ""
+    ... )
     >>> _removeUserToolboxesItem(tree)
     >>> etree.tostring(tree)
     b''
@@ -545,12 +567,16 @@ def _expandAddonsItem(node):
 def _expandItems(node, items, itemTag):
     """Expand items from file
 
-    >>> tree = etree.fromstring('')
-    >>> items = etree.fromstring('g.regionGRASS region management')
-    >>> _expandItems(tree, items, 'module-item')
+    >>> tree = etree.fromstring(
+    ...     ''
+    ... )
+    >>> items = etree.fromstring(
+    ...     'g.regionGRASS region management'
+    ... )
+    >>> _expandItems(tree, items, "module-item")
     >>> etree.tostring(tree)
     b'g.regionGRASS region management'
-    """
+    """  # noqa: E501
     for moduleItem in node.findall(".//" + itemTag):
         itemName = moduleItem.get("name")
         moduleNode = items.find('.//%s[@name="%s"]' % (itemTag, itemName))
@@ -569,19 +595,19 @@ def _expandRuntimeModules(node, loadMetadata=True):
     If loadMetadata is False, modules are not called,
     useful for incompatible addons.
 
-    >>> tree = etree.fromstring(''
-    ...                         ''
-    ...                         '')
+    >>> tree = etree.fromstring(
+    ...     "" '' ""
+    ... )
     >>> _expandRuntimeModules(tree)
     >>> etree.tostring(tree)
     b'g.regionManages the boundary definitions for the geographic region.general,settings,computational region,extent,resolution,level1'
-    >>> tree = etree.fromstring(''
-    ...                         ''
-    ...                         '')
+    >>> tree = etree.fromstring(
+    ...     "" '' ""
+    ... )
     >>> _expandRuntimeModules(tree)
     >>> etree.tostring(tree)
     b'm.projConverts coordinates from one projection to another (cs2cs frontend).miscellaneous,projection,transformation'
-    """
+    """  # noqa: E501
     hasErrors = False
     modules = node.findall(".//module-item")
     for module in modules:
@@ -621,7 +647,7 @@ def _escapeXML(text):
     Duplicate function in core/toolboxes and probably also in man compilation
     and some existing Python package.
 
-    >>> _escapeXML('<>&')
+    >>> _escapeXML("<>&")
     '&lt;>&'
     """
     return text.replace("<", "<").replace("&", "&").replace(">", ">")
@@ -659,9 +685,11 @@ def _addHandlers(node):
 def _convertTag(node, old, new):
     """Converts tag name.
 
-    >>> tree = etree.fromstring('')
-    >>> _convertTag(tree, 'toolbox', 'menu')
-    >>> _convertTag(tree, 'module-item', 'menuitem')
+    >>> tree = etree.fromstring(
+    ...     ""
+    ... )
+    >>> _convertTag(tree, "toolbox", "menu")
+    >>> _convertTag(tree, "module-item", "menuitem")
     >>> etree.tostring(tree)
     b''
     """
@@ -672,12 +700,14 @@ def _convertTag(node, old, new):
 def _convertTagAndRemoveAttrib(node, old, new):
     """Converts tag name and removes attributes.
 
-    >>> tree = etree.fromstring('')
-    >>> _convertTagAndRemoveAttrib(tree, 'toolbox', 'menu')
-    >>> _convertTagAndRemoveAttrib(tree, 'module-item', 'menuitem')
+    >>> tree = etree.fromstring(
+    ...     ''
+    ... )
+    >>> _convertTagAndRemoveAttrib(tree, "toolbox", "menu")
+    >>> _convertTagAndRemoveAttrib(tree, "module-item", "menuitem")
     >>> etree.tostring(tree)
     b''
-    """
+    """  # noqa: E501
     for n in node.findall(".//%s" % old):
         n.tag = new
         n.attrib = {}
@@ -686,11 +716,13 @@ def _convertTagAndRemoveAttrib(node, old, new):
 def _convertTree(root):
     """Converts tree to be the form readable by core/menutree.py.
 
-    >>> tree = etree.fromstring('g.region')
+    >>> tree = etree.fromstring(
+    ...     'g.region'
+    ... )
     >>> _convertTree(tree)
     >>> etree.tostring(tree)
     b'g.region'
-    """
+    """  # noqa: E501
     root.attrib = {}
     label = root.find("label")
     # must check because of inconsistent XML menudata file
diff --git a/gui/wxpython/core/treemodel.py b/gui/wxpython/core/treemodel.py
index 1c1fc2deee9..4191f0cc6c8 100644
--- a/gui/wxpython/core/treemodel.py
+++ b/gui/wxpython/core/treemodel.py
@@ -15,6 +15,7 @@
 
 @author Anna Petrasova 
 """
+
 import copy
 
 from grass.script.utils import naturally_sort
@@ -239,6 +240,52 @@ def match(self, key, value):
         return False
 
 
+class DictFilterNode(DictNode):
+    """Node which has data in a form of dictionary and can be filtered."""
+
+    def __init__(self, data=None):
+        super().__init__(data=data)
+
+    def match(self, method="exact", **kwargs):
+        """Method used for searching according to given parameters.
+
+        :param str method: 'exact' for exact match or
+                           'filtering' for filtering by type/name
+        :param kwargs key-value to be matched, filtering method uses 'type' and 'name'
+        :return bool: True if an entry matching given parameters was found
+        """
+        if not kwargs:
+            return False
+
+        if method == "exact":
+            return self._match_exact(**kwargs)
+        elif method == "filtering":
+            return self._match_filtering(**kwargs)
+
+    def _match_exact(self, **kwargs):
+        """Match method for exact matching."""
+        for key, value in kwargs.items():
+            if not (key in self.data and self.data[key] == value):
+                return False
+        return True
+
+    def _match_filtering(self, **kwargs):
+        """Match method for filtering."""
+        if (
+            "type" in kwargs
+            and "type" in self.data
+            and kwargs["type"] != self.data["type"]
+        ):
+            return False
+        if (
+            "name" in kwargs
+            and "name" in self.data
+            and not kwargs["name"].search(self.data["name"])
+        ):
+            return False
+        return True
+
+
 class ModuleNode(DictNode):
     """Node representing module."""
 
diff --git a/gui/wxpython/core/workspace.py b/gui/wxpython/core/workspace.py
index 82d05d89342..6ff1345c884 100644
--- a/gui/wxpython/core/workspace.py
+++ b/gui/wxpython/core/workspace.py
@@ -1768,8 +1768,8 @@ def read(self, parent):
                 parent=parent,
                 message=_(
                     "Some lines were skipped when reading settings "
-                    "from file <%(file)s>.\nSee 'Command output' window for details.\n\n"
-                    "Number of skipped lines: %(line)d"
+                    "from file <%(file)s>.\nSee 'Command output' window for details."
+                    "\n\nNumber of skipped lines: %(line)d"
                 )
                 % {"file": self.filename, "line": self.num_error},
                 caption=_("Warning"),
diff --git a/gui/wxpython/core/ws.py b/gui/wxpython/core/ws.py
index 32dec87a05d..f705962f9b2 100644
--- a/gui/wxpython/core/ws.py
+++ b/gui/wxpython/core/ws.py
@@ -16,6 +16,7 @@
 
 @author Stepan Turek  (mentor: Martin Landa)
 """
+
 import sys
 import copy
 import time
@@ -227,7 +228,8 @@ def _getRegionDict(self, env):
         return region
 
     def _createRegionStr(self, region):
-        """Create string for GRASS_REGION env variable from  dict created by _getRegionDict."""
+        """Create string for GRASS_REGION env variable from  dict created
+        by _getRegionDict."""
         regionStr = ""
         for k, v in region.items():
             item = k + ": " + str(v)
diff --git a/gui/wxpython/datacatalog/dialogs.py b/gui/wxpython/datacatalog/dialogs.py
index 948238c7146..5e463e83543 100644
--- a/gui/wxpython/datacatalog/dialogs.py
+++ b/gui/wxpython/datacatalog/dialogs.py
@@ -14,7 +14,6 @@
 @author Anna Petrasova 
 """
 
-
 import wx
 from gui_core.widgets import FloatValidator, IntegerValidator
 from core.giface import Notification
diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py
index 02d68f938a1..cfe7fe7a43c 100644
--- a/gui/wxpython/datacatalog/tree.py
+++ b/gui/wxpython/datacatalog/tree.py
@@ -18,6 +18,7 @@
 @author Anna Petrasova (kratochanna gmail com)
 @author Linda Kladivova (l.kladivova@seznam.cz)
 """
+
 import os
 import re
 import copy
@@ -37,7 +38,7 @@
 )
 from gui_core.dialogs import TextEntryDialog
 from core.giface import StandaloneGrassInterface
-from core.treemodel import TreeModel, DictNode
+from core.treemodel import TreeModel, DictFilterNode
 from gui_core.treeview import TreeView
 from gui_core.wrap import Menu
 from datacatalog.dialogs import CatalogReprojectionDialog
@@ -170,7 +171,7 @@ def OnOK(self, event):
             self.EndModal(wx.ID_OK)
 
 
-class DataCatalogNode(DictNode):
+class DataCatalogNode(DictFilterNode):
     """Node representing item in datacatalog."""
 
     def __init__(self, data=None):
@@ -196,36 +197,6 @@ def label(self):
 
         return _("{name}").format(**data)
 
-    def match(self, method="exact", **kwargs):
-        """Method used for searching according to given parameters.
-
-        :param method: 'exact' for exact match or 'filtering' for filtering by type/name
-        :param kwargs key-value to be matched, filtering method uses 'type' and 'name'
-               where 'name' is compiled regex
-        """
-        if not kwargs:
-            return False
-
-        if method == "exact":
-            for key, value in kwargs.items():
-                if not (key in self.data and self.data[key] == value):
-                    return False
-            return True
-        # for filtering
-        if (
-            "type" in kwargs
-            and "type" in self.data
-            and kwargs["type"] != self.data["type"]
-        ):
-            return False
-        if (
-            "name" in kwargs
-            and "name" in self.data
-            and not kwargs["name"].search(self.data["name"])
-        ):
-            return False
-        return True
-
 
 class DataCatalogTree(TreeView):
     """Tree structure visualizing and managing grass database.
@@ -610,9 +581,11 @@ def _reloadTreeItems(self, full=False):
         """Updates grass databases, locations, mapsets and layers in the tree.
 
         It runs in thread, so it should not directly interact with GUI.
-        In case of any errors it returns the errors as a list of strings, otherwise None.
+        In case of any errors it returns the errors as a list of strings, otherwise
+        None.
 
-        Option full=True forces full reload, full=False will behave based on user settings.
+        Option full=True forces full reload, full=False will behave based on user
+        settings.
         """
         errors = []
         for grassdatabase in self.grassdatabases:
@@ -899,10 +872,10 @@ def OnDoubleClick(self, node):
                     dlg = wx.MessageDialog(
                         parent=self,
                         message=_(
-                            "Map <{map_name}@{map_mapset}> is not in the current project. "
-                            "To be able to display it you need to switch to <{map_location}> "
-                            "project. Note that if you switch there all current "
-                            "Map Displays will be closed.\n\n"
+                            "Map <{map_name}@{map_mapset}> is not in the current "
+                            "project. To be able to display it you need to switch to "
+                            "<{map_location}> project. Note that if you switch there "
+                            "all current Map Displays will be closed.\n\n"
                             "Do you want to switch anyway?"
                         ).format(
                             map_name=selected_layer.data["name"],
@@ -1705,7 +1678,8 @@ def DisplayLayer(self):
             )
             names[self.selected_layer[i].data["type"]].append(name)
             all_names.append(name)
-        # if self.selected_location[0].data['name'] == gisenv()['LOCATION_NAME'] and self.selected_mapset[0]:
+        # if self.selected_location[0].data['name'] == gisenv()['LOCATION_NAME'] and
+        # self.selected_mapset[0]:
         for ltype in names:
             if names[ltype]:
                 self._giface.lmgr.AddMaps(list(reversed(names[ltype])), ltype, True)
@@ -1741,7 +1715,8 @@ def OnEndDrag(self, node, event):
                 ):
                     GMessage(
                         _(
-                            "To move or copy maps to other mapsets, unlock editing of other mapsets"
+                            "To move or copy maps to other mapsets, unlock editing of "
+                            "other mapsets"
                         ),
                         parent=self,
                     )
diff --git a/gui/wxpython/dbmgr/base.py b/gui/wxpython/dbmgr/base.py
index 7538ee8a450..482c3ccf7db 100644
--- a/gui/wxpython/dbmgr/base.py
+++ b/gui/wxpython/dbmgr/base.py
@@ -26,7 +26,8 @@
 
 @author Jachym Cepicky 
 @author Martin Landa 
-@author Refactoring by Stepan Turek  (GSoC 2012, mentor: Martin Landa)
+@author Refactoring by Stepan Turek 
+        (GSoC 2012, mentor: Martin Landa)
 """
 
 import os
@@ -301,8 +302,8 @@ def LoadData(self, layer, columns=None, where=None, sql=None):
                     GWarning(
                         parent=self,
                         message=_(
-                            "Incorrect encoding {enc} used. Set encoding in GUI Settings"
-                            " or set GRASS_DB_ENCODING variable."
+                            "Incorrect encoding {enc} used. Set encoding in GUI "
+                            "Settings or set GRASS_DB_ENCODING variable."
                         ).format(enc=enc),
                     )
 
@@ -317,13 +318,16 @@ def LoadData(self, layer, columns=None, where=None, sql=None):
                 if len(record) > show_max:
                     record = record[:show_max]
                 # TODO: The real fix here is to use JSON output from v.db.select or
-                # proper CSV output and real CSV reader here (Python csv and json packages).
+                # proper CSV output and real CSV reader here (Python csv and json
+                # packages).
                 raise GException(
                     _(
                         "Unable to read the table <{table}> from the database due"
-                        " to seemingly inconsistent number of columns in the data transfer."
+                        " to seemingly inconsistent number of columns in the data"
+                        " transfer."
                         " Check row: {row}..."
-                        " Likely, a newline character is present in the attribute value starting with: '{value}'"
+                        " Likely, a newline character is present in the attribute value"
+                        " starting with: '{value}'"
                         " Use the v.db.select module to investigate."
                     ).format(table=tableName, row=" | ".join(record), value=last)
                 )
@@ -404,8 +408,8 @@ def AddDataRow(self, i, record, columns, keyId):
                         parent=self,
                         message=_(
                             "Error loading attribute data. "
-                            "Record number: %(rec)d. Unable to convert value '%(val)s' in "
-                            "key column (%(key)s) to integer.\n\n"
+                            "Record number: %(rec)d. Unable to convert value '%(val)s' "
+                            "in key column (%(key)s) to integer.\n\n"
                             "Details: %(detail)s"
                         )
                         % {"rec": i + 1, "val": value, "key": keyColumn, "detail": e},
@@ -856,9 +860,11 @@ def UpdateDialog(self, layer):
         if layer in self.dbMgrData["mapDBInfo"].layers.keys():
             # delete page
             # dragging pages disallowed
-            # if self.browsePage.GetPageText(page).replace('Layer ', '').strip() == str(layer):
-            # self.browsePage.DeletePage(page)
-            # break
+            # if self.browsePage.GetPageText(page).replace("Layer ", "").strip() == str(
+            #     layer
+            # ):
+            #     self.browsePage.DeletePage(page)
+            #     break
             if self.pages["browse"]:
                 self.pages["browse"].DeletePage(layer)
             if self.pages["manageTable"]:
@@ -2319,7 +2325,8 @@ def AddLayer(self, layer, pos=-1):
         :param pos: position of tab, if -1 it is added to end
 
         :return: True if layer was added
-        :return: False if layer was not added - layer has been already added or does not exist
+        :return: False if layer was not added - layer has been already added or does
+                 not exist
         """
         if layer in self.layers or layer not in self.parentDbMgrBase.GetVectorLayers():
             return False
@@ -2839,7 +2846,8 @@ def _updateTableColumnWidgetChoices(self, table):
         self.FindWindowById(
             self.pages["browse"].layerPage[self.selLayer]["whereColumn"]
         ).SetItems(cols)
-        # Browse data page SQL Query Builder page SQL builder frame ListBox column names widget
+        # Browse data page SQL Query Builder page SQL builder frame ListBox column
+        # names widget
         if self.pages["browse"].builder:
             self.pages["browse"].builder.list_columns.Set(cols)
         # Browse data page column Field calculator frame ListBox column names widget
@@ -3135,7 +3143,8 @@ def __init__(self, parent, id, parentDialog, style=wx.BK_DEFAULT):
         #        len(self.defaultConnect['database']) == 0:
         #     GWarning(parent = self.parent,
         #              message = _("Unknown default DB connection. "
-        #                          "Please define DB connection using db.connect module."))
+        #                          "Please define DB connection using db.connect"
+        #                          "module."))
 
         self.defaultTables = self._getTables(
             self.defaultConnect["driver"], self.defaultConnect["database"]
@@ -3536,9 +3545,11 @@ def _createModifyPage(self):
 
         # events
         self.modifyLayerWidgets["layer"][1].Bind(wx.EVT_COMBOBOX, self.OnChangeLayer)
-        # self.modifyLayerWidgets['driver'][1].Bind(wx.EVT_CHOICE, self.OnDriverChanged)
-        # self.modifyLayerWidgets['database'][1].Bind(wx.EVT_TEXT_ENTER, self.OnDatabaseChanged)
-        # self.modifyLayerWidgets['table'][1].Bind(wx.EVT_CHOICE, self.OnTableChanged)
+        # self.modifyLayerWidgets["driver"][1].Bind(wx.EVT_CHOICE, self.OnDriverChanged)
+        # self.modifyLayerWidgets["database"][1].Bind(
+        #     wx.EVT_TEXT_ENTER, self.OnDatabaseChanged
+        # )
+        # self.modifyLayerWidgets["table"][1].Bind(wx.EVT_CHOICE, self.OnTableChanged)
 
         btnModify = Button(
             self.modifyPanel, wx.ID_DELETE, _("&Modify layer"), size=(125, -1)
diff --git a/gui/wxpython/dbmgr/dialogs.py b/gui/wxpython/dbmgr/dialogs.py
index 5778c8a0fcd..1a3c3af6ee2 100644
--- a/gui/wxpython/dbmgr/dialogs.py
+++ b/gui/wxpython/dbmgr/dialogs.py
@@ -14,7 +14,8 @@
 (>=v2). Read the file COPYING that comes with GRASS for details.
 
 @author Martin Landa 
-@author Refactoring by Stepan Turek  (GSoC 2012, mentor: Martin Landa)
+@author Refactoring by Stepan Turek 
+        (GSoC 2012, mentor: Martin Landa)
 """
 
 import wx
@@ -237,7 +238,8 @@ def GetSQLString(self, updateValues=False):
                             GError(
                                 parent=self,
                                 message=_(
-                                    "Column <%(col)s>: Value '%(value)s' needs to be entered as %(type)s."
+                                    "Column <%(col)s>: Value '%(value)s' needs to be "
+                                    "entered as %(type)s."
                                 )
                                 % {
                                     "col": name,
diff --git a/gui/wxpython/dbmgr/manager.py b/gui/wxpython/dbmgr/manager.py
index 40f879a1e55..c866bd55650 100644
--- a/gui/wxpython/dbmgr/manager.py
+++ b/gui/wxpython/dbmgr/manager.py
@@ -19,7 +19,8 @@
 
 @author Jachym Cepicky 
 @author Martin Landa 
-@author Refactoring by Stepan Turek  (GSoC 2012, mentor: Martin Landa)
+@author Refactoring by Stepan Turek 
+        (GSoC 2012, mentor: Martin Landa)
 """
 
 import os
diff --git a/gui/wxpython/dbmgr/sqlbuilder.py b/gui/wxpython/dbmgr/sqlbuilder.py
index d69a6cace62..a4bc926463c 100644
--- a/gui/wxpython/dbmgr/sqlbuilder.py
+++ b/gui/wxpython/dbmgr/sqlbuilder.py
@@ -21,7 +21,8 @@
 @author Jachym Cepicky  (original author)
 @author Martin Landa 
 @author Hamish Bowman 
-@author Refactoring, SQLBUilderUpdate by Stepan Turek  (GSoC 2012, mentor: Martin Landa)
+@author Refactoring, SQLBUilderUpdate by Stepan Turek 
+        (GSoC 2012, mentor: Martin Landa)
 """
 
 import os
diff --git a/gui/wxpython/docs/CMakeLists.txt b/gui/wxpython/docs/CMakeLists.txt
new file mode 100644
index 00000000000..8e32eee7424
--- /dev/null
+++ b/gui/wxpython/docs/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(wxpython_html_files)
+
+add_custom_command(
+  OUTPUT ${GISBASE}/docs/html/wxGUI.components.html
+  COMMAND
+    ${grass_env_command} ${PYTHON_EXECUTABLE} ${MKHTML_PY} wxGUI.components
+    ${GRASS_VERSION_DATE} > ${GISBASE}/docs/html/wxGUI.components.html
+  COMMENT "Creating ${GISBASE}/docs/html/wxGUI.components.html"
+  DEPENDS GUI_WXPYTHON LIB_PYTHON)
+
+list(APPEND wxpython_html_files ${GISBASE}/docs/html/wxGUI.components.html)
+
+add_custom_target(wxpython_docs DEPENDS ${wxpython_html_files})
diff --git a/gui/wxpython/docs/wxgui_sphinx/conf.py b/gui/wxpython/docs/wxgui_sphinx/conf.py
index ba3d4c4c6e8..ef2a4a3849f 100644
--- a/gui/wxpython/docs/wxgui_sphinx/conf.py
+++ b/gui/wxpython/docs/wxgui_sphinx/conf.py
@@ -30,8 +30,11 @@
 footer_tmpl = string.Template(
     r"""
 {% block footer %}
-

Help Index | Topics Index | Keywords Index | Full Index

-

© 2003-${year} GRASS Development Team, GRASS GIS ${grass_version} Reference Manual

+

Help Index | Topics Index +| Keywords Index +| Full Index

+

© 2003-${year} GRASS Development Team, +GRASS GIS ${grass_version} Reference Manual

{% endblock %} """ ) diff --git a/gui/wxpython/gcp/manager.py b/gui/wxpython/gcp/manager.py index 451f3c2c833..3e948dc3c91 100644 --- a/gui/wxpython/gcp/manager.py +++ b/gui/wxpython/gcp/manager.py @@ -1549,7 +1549,7 @@ def SaveGCPs(self, event): f.write("#\tsource\t\ttarget\t\tstatus\n") f.write("#\teast\tnorth\teast\tnorth\t(1=ok, 0=ignore)\n") f.write( - "#----------------------- ----------------------- ---------------\n" + "#----------------------- ----------------------- ---------------\n" # noqa: E501 ) for index in range(self.list.GetItemCount()): @@ -1694,7 +1694,8 @@ def ReloadGCPs(self, event): targetMapWin.UpdateMap(render=False, renderVector=False) def OnFocus(self, event): - # TODO: it is here just to remove old or obsolete beavior of base class gcp/MapPanel? + # TODO: it is here just to remove old or obsolete beavior of base class + # gcp/MapPanel? # self.grwiz.SwitchEnv('source') pass @@ -2033,16 +2034,19 @@ def OnGROrder(self, event): if self.gr_order == 1: minNumOfItems = 3 - # self.SetStatusText(_('Insufficient points, 3+ points needed for 1st order')) + # self.SetStatusText( + # _('Insufficient points, 3+ points needed for 1st order')) elif self.gr_order == 2: minNumOfItems = 6 diff = 6 - numOfItems - # self.SetStatusText(_('Insufficient points, 6+ points needed for 2nd order')) + # self.SetStatusText( + # _('Insufficient points, 6+ points needed for 2nd order')) elif self.gr_order == 3: minNumOfItems = 10 - # self.SetStatusText(_('Insufficient points, 10+ points needed for 3rd order')) + # self.SetStatusText( + # _('Insufficient points, 10+ points needed for 3rd order')) for i in range(minNumOfItems - numOfItems): self.AddGCP(None) @@ -2972,7 +2976,8 @@ def __init__( btnSave.Bind(wx.EVT_BUTTON, self.OnSave) btnSave.SetToolTip( _( - "Apply and save changes to user settings file (default for next sessions)" + "Apply and save changes to user settings file (default for next " + "sessions)" ) ) btnClose.Bind(wx.EVT_BUTTON, self.OnClose) diff --git a/gui/wxpython/gcp/statusbar.py b/gui/wxpython/gcp/statusbar.py index 1d10ad0b9b4..1424f7f4846 100644 --- a/gui/wxpython/gcp/statusbar.py +++ b/gui/wxpython/gcp/statusbar.py @@ -16,7 +16,6 @@ @author Anna Kratochvilova (statusbar refactoring) """ - import wx from core.gcmd import GMessage diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index 6b4e84a2681..b33c5b6d4e4 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -2783,7 +2783,7 @@ def __init__(self): inputs = list() outputs = list() -""" +""" # noqa: E501 ) for item in self.model.GetItems(): diff --git a/gui/wxpython/gmodeler/panels.py b/gui/wxpython/gmodeler/panels.py index 1e650ffaa1c..76a5237448e 100644 --- a/gui/wxpython/gmodeler/panels.py +++ b/gui/wxpython/gmodeler/panels.py @@ -23,7 +23,6 @@ import stat import tempfile import random -import six import math import wx @@ -1227,7 +1226,7 @@ def OnModelProperties(self, event): dlg.Init(properties) if dlg.ShowModal() == wx.ID_OK: self.ModelChanged() - for key, value in six.iteritems(dlg.GetValues()): + for key, value in dlg.GetValues().items(): properties[key] = value for action in self.model.GetItems(objType=ModelAction): action.GetTask().set_flag("overwrite", properties["overwrite"]) @@ -1459,7 +1458,7 @@ def OnAdd(self, event): def UpdateModelVariables(self): """Update model variables""" variables = dict() - for values in six.itervalues(self.list.GetData()): + for values in self.list.GetData().values(): name = values[0] variables[name] = {"type": str(values[1])} if values[2]: diff --git a/gui/wxpython/gui_core/dialogs.py b/gui/wxpython/gui_core/dialogs.py index 4d292854a11..e4c9cd50081 100644 --- a/gui/wxpython/gui_core/dialogs.py +++ b/gui/wxpython/gui_core/dialogs.py @@ -107,7 +107,8 @@ def __layout(self): self.sizer.Add(self.dataSizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) - # self.sizer.Add(item = self.informLabel, proportion = 0, flag = wx.ALL, border = 5) + # self.sizer.Add(item = self.informLabel, proportion = 0, + # flag = wx.ALL, border = 5) self.sizer.Add(btnSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) def ValidatorCallback(self, win): @@ -304,7 +305,8 @@ def __init__( :param title: window title :param disableAdd: disable 'add layer' checkbox :param disableTable: disable 'create table' checkbox - :param showType: True to show feature type selector (used for creating new empty OGR layers) + :param showType: True to show feature type selector (used for creating new + empty OGR layers) :return: dialog instance """ @@ -2599,7 +2601,8 @@ def GetFonts(self): return fontdict, fontdict_reverse, fontlist def RenderText(self, font, text, size): - """Renders an example text with the selected font and resets the bitmap widget""" + """Renders an example text with the selected font and resets the bitmap + widget""" env = os.environ.copy() driver = UserSettings.Get(group="display", key="driver", subkey="type") if driver == "png": diff --git a/gui/wxpython/gui_core/forms.py b/gui/wxpython/gui_core/forms.py index 87d10c81815..937b31321a9 100644 --- a/gui/wxpython/gui_core/forms.py +++ b/gui/wxpython/gui_core/forms.py @@ -1548,8 +1548,8 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar selection.SetValue(value) formatSelector = True - # A gselect.Select is a combobox with two children: a textctl and a popupwindow; - # we target the textctl here + # A gselect.Select is a combobox with two children: a textctl + # and a popupwindow; we target the textctl here textWin = selection.GetTextCtrl() if globalvar.CheckWxVersion([3]): p["wxId"] = [ @@ -1572,44 +1572,63 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar win.Bind(wx.EVT_TEXT, self.OnUpdateSelection) win.Bind(wx.EVT_TEXT, self.OnSetValue) - # if formatSelector and p.get('age', 'old') == 'old': + # if formatSelector and p.get("age", "old") == "old": # # OGR supported (read-only) # self.hsizer = wx.BoxSizer(wx.HORIZONTAL) - - # self.hsizer.Add(item = selection, - # flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_TOP, - # border = 5) - + # + # self.hsizer.Add( + # item=selection, + # flag=wx.ADJUST_MINSIZE + # | wx.BOTTOM + # | wx.LEFT + # | wx.RIGHT + # | wx.TOP + # | wx.ALIGN_TOP, + # border=5, + # ) + # # # format (native / ogr) - # rbox = wx.RadioBox(parent = which_panel, id = wx.ID_ANY, - # label = " %s " % _("Format"), - # style = wx.RA_SPECIFY_ROWS, - # choices = [_("Native / Linked OGR"), _("Direct OGR")]) - # if p.get('value', '').lower().rfind('@ogr') > -1: + # rbox = wx.RadioBox( + # parent=which_panel, + # id=wx.ID_ANY, + # label=" %s " % _("Format"), + # style=wx.RA_SPECIFY_ROWS, + # choices=[_("Native / Linked OGR"), _("Direct OGR")], + # ) + # if p.get("value", "").lower().rfind("@ogr") > -1: # rbox.SetSelection(1) - # rbox.SetName('VectorFormat') + # rbox.SetName("VectorFormat") # rbox.Bind(wx.EVT_RADIOBOX, self.OnVectorFormat) - - # self.hsizer.Add(item = rbox, - # flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | - # wx.RIGHT | wx.ALIGN_TOP, - # border = 5) - - # ogrSelection = gselect.GdalSelect(parent = self, panel = which_panel, ogr = True, - # default = 'dir', - # exclude = ['file']) + # + # self.hsizer.Add( + # item=rbox, + # flag=wx.ADJUST_MINSIZE + # | wx.BOTTOM + # | wx.LEFT + # | wx.RIGHT + # | wx.ALIGN_TOP, + # border=5, + # ) + # + # ogrSelection = gselect.GdalSelect( + # parent=self, + # panel=which_panel, + # ogr=True, + # default="dir", + # exclude=["file"], + # ) # self.Bind(gselect.EVT_GDALSELECT, self.OnUpdateSelection) # self.Bind(gselect.EVT_GDALSELECT, self.OnSetValue) - # ogrSelection.SetName('OgrSelect') + # ogrSelection.SetName("OgrSelect") # ogrSelection.Hide() # which_sizer.Add(item = self.hsizer, proportion = 0) - # p['wxId'].append(rbox.GetId()) - # p['wxId'].append(ogrSelection.GetId()) + # p["wxId"].append(rbox.GetId()) + # p["wxId"].append(ogrSelection.GetId()) # for win in ogrSelection.GetDsnWin(): - # p['wxId'].append(win.GetId()) + # p["wxId"].append(win.GetId()) # else: which_sizer.Add( selection, @@ -1660,7 +1679,8 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar bb.Bind(wx.EVT_BUTTON, self.OnTimelineTool) bb.SetToolTip( _( - "Show graphical representation of temporal extent of dataset(s) ." + "Show graphical representation of temporal extent " + "of dataset(s)." ) ) p["wxId"].append(bb.GetId()) @@ -1935,9 +1955,9 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar else: this_sizer = which_sizer colorSize = 150 - # For color selectors, this is a three-member array, holding the IDs of - # the color picker, the text control for multiple colors (or None), - # and either a "transparent" checkbox or None + # For color selectors, this is a three-member array, holding the + # IDs of the color picker, the text control for multiple colors + # (or None), and either a "transparent" checkbox or None p["wxId"] = [None] * 3 if p.get("multiple", False): txt = TextCtrl(parent=which_panel, id=wx.ID_ANY) @@ -2063,7 +2083,8 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar try: ifbb.AppendText(line) except UnicodeDecodeError: - # remove non-ascii characters on encoding mismatch (file vs OS) + # remove non-ascii characters on encoding + # mismatch (file vs OS) ifbb.AppendText(line.translate(None, nonascii)) ifbb.SetInsertionPoint(0) @@ -2818,8 +2839,8 @@ def OnColorChange(self, event): else: colorchooser = wx.FindWindowById(p["wxId"][0]) new_color = colorchooser.GetValue()[:] - # This is weird: new_color is a 4-tuple and new_color[:] is a 3-tuple - # under wx2.8.1 + # This is weird: new_color is a 4-tuple and new_color[:] is + # a 3-tuple under wx2.8.1 new_label = utils.rgb2str.get( new_color, ":".join(list(map(str, new_color))) ) @@ -3306,7 +3327,8 @@ def OnInit(self): task.params = [ { "name": "text", - "description": "Descriptions go into tooltips if labels are present, like this one", + "description": "Descriptions go into tooltips if labels are present, " + "like this one", "label": "Enter some text", "key_desc": ["value"], "values_desc": [], @@ -3334,7 +3356,8 @@ def OnInit(self): }, { "name": "plain_color", - "description": "This is a plain color, and it is a compulsory parameter", + "description": "This is a plain color, and it is a compulsory " + "parameter", "required": False, "gisprompt": True, "prompt": "color", @@ -3400,7 +3423,8 @@ def OnInit(self): }, { "name": "b", - "description": "pre-filled flag, will appear in options since it is not required", + "description": "pre-filled flag, will appear in options since it is " + "not required", "value": True, "suppress_required": False, }, diff --git a/gui/wxpython/gui_core/ghelp.py b/gui/wxpython/gui_core/ghelp.py index 1ac64bb6609..6c87b444081 100644 --- a/gui/wxpython/gui_core/ghelp.py +++ b/gui/wxpython/gui_core/ghelp.py @@ -188,16 +188,26 @@ def _pageInfo(self): # show only basic info # row += 1 - # infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY, - # label = '%s:' % _('GIS Library Revision')), - # pos = (row, 0), - # flag = wx.ALIGN_RIGHT) - - # infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY, - # label = vInfo['libgis_revision'] + ' (' + - # vInfo['libgis_date'].split(' ')[0] + ')'), - # pos = (row, 1), - # flag = wx.ALIGN_LEFT) + # infoGridSizer.Add( + # item=wx.StaticText( + # parent=infoTxt, id=wx.ID_ANY, label="%s:" % _("GIS Library Revision") + # ), + # pos=(row, 0), + # flag=wx.ALIGN_RIGHT, + # ) + # + # infoGridSizer.Add( + # item=wx.StaticText( + # parent=infoTxt, + # id=wx.ID_ANY, + # label=vInfo["libgis_revision"] + # + " (" + # + vInfo["libgis_date"].split(" ")[0] + # + ")", + # ), + # pos=(row, 1), + # flag=wx.ALIGN_LEFT, + # ) row += 2 infoGridSizer.Add( @@ -751,7 +761,8 @@ def __init__(self, parent, command, text, skipDescription, **kwargs): self.history.append(url) self.loaded = True else: - # FIXME: calling LoadPage() is strangely time-consuming (only first call) + # FIXME: calling LoadPage() is strangely time-consuming + # (only first call) # self.LoadPage(self.fspath + command + ".html") self.loaded = False else: diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index 859be0e132f..12773f1c449 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -117,7 +117,8 @@ def __init__( :param updateOnPopup: True for updating list of elements on popup :param onPopup: function to be called on Popup :param fullyQualified: True to provide fully qualified names (map@mapset) - :param extraItems: extra items to add (given as dictionary) - see gmodeler for usage + :param extraItems: extra items to add (given as dictionary) + - see gmodeler for usage :param layerTree: show only elements from given layer tree if not None :param validator: validator for TextCtrl """ @@ -2284,8 +2285,8 @@ def hasRastSameProjAsLocation(dsn, table=None): "r.external", quiet=True, read=True, flags="t", input=dsn ) - # v.external returns info for individual bands, however projection is shared by all bands -> - # (it is possible to take first line) + # v.external returns info for individual bands, however projection is + # shared by all bands -> (it is possible to take first line) lines = ret.splitlines() projectionMatch = "0" @@ -2983,7 +2984,8 @@ def _isMapSelected(self): return True def _chckMap(self): - """Check if selected map in 'input' widget is the same as selected map in lmgr""" + """Check if selected map in 'input' widget is the same as selected map in + lmgr""" if self._isMapSelected(): layerList = self.giface.GetLayerList() layerSelected = layerList.GetSelectedLayer() @@ -2997,8 +2999,8 @@ def _chckMap(self): return False GWarning( _( - "Input vector map <%s> and selected map <%s> in layer manager are different. " - "Operation canceled." + "Input vector map <%s> and selected map <%s> in layer manager " + "are different. Operation canceled." ) % (inputName["value"], str(layerSelected)) ) diff --git a/gui/wxpython/gui_core/menu.py b/gui/wxpython/gui_core/menu.py index 55ba0d40d48..3c1376cea0d 100644 --- a/gui/wxpython/gui_core/menu.py +++ b/gui/wxpython/gui_core/menu.py @@ -22,6 +22,7 @@ @author Vaclav Petras (menu customization) @author Tomas Zigo RecentFilesMenu """ + import re import os import wx diff --git a/gui/wxpython/gui_core/preferences.py b/gui/wxpython/gui_core/preferences.py index 257fafc4dca..96b7d339664 100644 --- a/gui/wxpython/gui_core/preferences.py +++ b/gui/wxpython/gui_core/preferences.py @@ -36,6 +36,7 @@ havePwd = False import wx +import wx.lib.agw.aui as aui import wx.lib.colourselect as csel import wx.lib.mixins.listctrl as listmix import wx.lib.scrolledpanel as SP @@ -112,7 +113,8 @@ def __init__( self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave) self.btnSave.SetToolTip( _( - "Apply and save changes to user settings file (default for next sessions)" + "Apply and save changes to user settings file (default for next " + "sessions)" ) ) self.btnSave.SetDefault() @@ -312,11 +314,103 @@ def _createGeneralPage(self, notebook): gridSizer.Add(askOnQuit, pos=(row, 0), span=(1, 2)) + # + # Selected text is copied to clipboard + # + row += 1 + copySelectedTextToClipboard = wx.CheckBox( + parent=panel, + id=wx.ID_ANY, + label=_( + "Automatically copy selected text to clipboard (in the Console tab)" + ), + name="IsChecked", + ) + copySelectedTextToClipboard.SetValue( + self.settings.Get( + group="manager", key="copySelectedTextToClipboard", subkey="enabled" + ) + ) + self.winId["manager:copySelectedTextToClipboard:enabled"] = ( + copySelectedTextToClipboard.GetId() + ) + + gridSizer.Add(copySelectedTextToClipboard, pos=(row, 0), span=(1, 2)) + + gridSizer.AddGrowableCol(0) + sizer.Add(gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5) + border.Add(sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=3) + + # + # Layout settings + # + box = StaticBox( + parent=panel, id=wx.ID_ANY, label=" {} ".format(_("Layout settings")) + ) + sizer = wx.StaticBoxSizer(box, wx.VERTICAL) + gridSizer = wx.GridBagSizer(hgap=3, vgap=3) + + row = 0 + defaultPos = wx.CheckBox( + parent=panel, + id=wx.ID_ANY, + label=_("Save current window layout as default"), + name="IsChecked", + ) + defaultPos.SetValue( + self.settings.Get(group="general", key="defWindowPos", subkey="enabled") + ) + defaultPos.SetToolTip( + wx.ToolTip( + _( + "Save current position and size of Layer Manager window and opened " + "Map Display window(s) and use as default for next sessions." + ) + ) + ) + self.winId["general:defWindowPos:enabled"] = defaultPos.GetId() + + gridSizer.Add(defaultPos, pos=(row, 0), span=(1, 2)) + + row += 1 + singleWinPanesLayoutPos = wx.CheckBox( + parent=panel, + id=wx.ID_ANY, + label=_("Save current single window panes layout as default"), + name="SingleWinPanesLayoutPos", + ) + singleWinPanesLayoutPos.SetValue( + self.settings.Get( + group="general", + key="singleWinPanesLayoutPos", + subkey="enabled", + ) + ) + singleWinPanesLayoutPos.SetToolTip( + wx.ToolTip( + _( + "Save current position and size of single-window mode panes" + " and use as default for next sessions." + ) + ) + ) + if not self.settings.Get( + group="appearance", + key="singleWindow", + subkey="enabled", + ): + singleWinPanesLayoutPos.Disable() + self.winId["general:singleWinPanesLayoutPos:enabled"] = ( + singleWinPanesLayoutPos.GetId() + ) + + gridSizer.Add(singleWinPanesLayoutPos, pos=(row, 0), span=(1, 2)) + row += 1 hideSearch = wx.CheckBox( parent=panel, id=wx.ID_ANY, - label=_("Hide '%s' tab (requires GUI restart)") % _("Tools"), + label=_("Hide '{}' tab (requires GUI restart)").format(_("Tools")), name="IsChecked", ) hideSearch.SetValue( @@ -330,7 +424,7 @@ def _createGeneralPage(self, notebook): hideHistory = wx.CheckBox( parent=panel, id=wx.ID_ANY, - label=_("Hide '%s' tab (requires GUI restart)") % _("History"), + label=_("Hide '{}' tab (requires GUI restart)").format(_("History")), name="IsChecked", ) hideHistory.SetValue( @@ -344,7 +438,7 @@ def _createGeneralPage(self, notebook): hidePyShell = wx.CheckBox( parent=panel, id=wx.ID_ANY, - label=_("Hide '%s' tab (requires GUI restart)") % _("Python"), + label=_("Hide '{}' tab (requires GUI restart)").format(_("Python")), name="IsChecked", ) hidePyShell.SetValue( @@ -353,33 +447,9 @@ def _createGeneralPage(self, notebook): self.winId["manager:hideTabs:pyshell"] = hidePyShell.GetId() gridSizer.Add(hidePyShell, pos=(row, 0), span=(1, 2)) - - # - # Selected text is copied to clipboard - # - row += 1 - copySelectedTextToClipboard = wx.CheckBox( - parent=panel, - id=wx.ID_ANY, - label=_( - "Automatically copy selected text to clipboard (in the Console tab)" - ), - name="IsChecked", - ) - copySelectedTextToClipboard.SetValue( - self.settings.Get( - group="manager", key="copySelectedTextToClipboard", subkey="enabled" - ) - ) - self.winId[ - "manager:copySelectedTextToClipboard:enabled" - ] = copySelectedTextToClipboard.GetId() - - gridSizer.Add(copySelectedTextToClipboard, pos=(row, 0), span=(1, 2)) - - gridSizer.AddGrowableCol(0) sizer.Add(gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5) border.Add(sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=3) + # # Data catalog settings # @@ -427,7 +497,6 @@ def _createGeneralPage(self, notebook): gridSizer.Add(posDisplay, pos=(row, 0), span=(1, 2)) row += 1 - posManager = wx.CheckBox( parent=panel, id=wx.ID_ANY, @@ -443,28 +512,6 @@ def _createGeneralPage(self, notebook): gridSizer.Add(posManager, pos=(row, 0), span=(1, 2)) - row += 1 - defaultPos = wx.CheckBox( - parent=panel, - id=wx.ID_ANY, - label=_("Save current window layout as default"), - name="IsChecked", - ) - defaultPos.SetValue( - self.settings.Get(group="general", key="defWindowPos", subkey="enabled") - ) - defaultPos.SetToolTip( - wx.ToolTip( - _( - "Save current position and size of Layer Manager window and opened " - "Map Display window(s) and use as default for next sessions." - ) - ) - ) - self.winId["general:defWindowPos:enabled"] = defaultPos.GetId() - - gridSizer.Add(defaultPos, pos=(row, 0), span=(1, 2)) - gridSizer.AddGrowableCol(0) sizer.Add(gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5) border.Add(sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=3) @@ -1423,9 +1470,9 @@ def _createLayersPage(self, notebook): subkey=["transparent", "enabled"], ) ) - self.winId[ - "vectorLayer:featureColor:transparent:enabled" - ] = transpFeature.GetId() + self.winId["vectorLayer:featureColor:transparent:enabled"] = ( + transpFeature.GetId() + ) gridSizer.Add(transpFeature, pos=(row, col + 1), flag=wx.ALIGN_CENTER_VERTICAL) # area fill color @@ -1944,6 +1991,24 @@ def _updateSettings(self): group="general", key="defWindowPos", subkey="dim", value=dim ) + # + # update single window panes layout + # + single_win_panes_layout_pos = self.settings.Get( + group="general", + key="singleWinPanesLayoutPos", + subkey="enabled", + ) + if single_window and single_win_panes_layout_pos: + aui_manager = aui.GetManager(self.parent) + if aui_manager: + self.settings.Set( + group="general", + key="singleWinPanesLayoutPos", + subkey="pos", + value=aui_manager.SavePerspective(), + ) + return True def OnCheckColorTable(self, event): diff --git a/gui/wxpython/gui_core/pystc.py b/gui/wxpython/gui_core/pystc.py index b11bf0f8418..bf268f88f33 100644 --- a/gui/wxpython/gui_core/pystc.py +++ b/gui/wxpython/gui_core/pystc.py @@ -15,7 +15,6 @@ @author Anna Petrasova (dark theme) """ - import keyword import wx diff --git a/gui/wxpython/gui_core/query.py b/gui/wxpython/gui_core/query.py index 638a64fa948..3a250af4d42 100644 --- a/gui/wxpython/gui_core/query.py +++ b/gui/wxpython/gui_core/query.py @@ -13,6 +13,7 @@ @author Anna Kratochvilova """ + import wx from gui_core.treeview import TreeListView diff --git a/gui/wxpython/gui_core/treeview.py b/gui/wxpython/gui_core/treeview.py index 53f5852dff9..01bbe87d493 100644 --- a/gui/wxpython/gui_core/treeview.py +++ b/gui/wxpython/gui_core/treeview.py @@ -279,8 +279,8 @@ def __init__(self, model=None): wx.Frame.__init__(self, None, title="Test tree") panel = wx.Panel(self) - # self.tree = TreeListView(model=model, parent=panel, columns=['col1', 'xxx']) - # self.tree = TreeView(model=model, parent=panel) + # self.tree = TreeListView(model=model, parent=panel, columns=["col1", "xxx"]) + # self.tree = TreeView(model=model, parent=panel) self.tree = CTreeView(model=model, parent=panel) self.tree.selectionChanged.connect(self.OnSelChanged) self.tree.itemActivated.connect(self.OnItemActivated) diff --git a/gui/wxpython/gui_core/widgets.py b/gui/wxpython/gui_core/widgets.py index 3ced80291ce..7630c6f03ad 100644 --- a/gui/wxpython/gui_core/widgets.py +++ b/gui/wxpython/gui_core/widgets.py @@ -43,10 +43,11 @@ @author Martin Landa (Google SoC 2008/2010) @author Enhancements by Michael Barton @author Anna Kratochvilova (Google SoC 2011) -@author Stepan Turek (ManageSettingsWidget - created from GdalSelect) -@author Matej Krejci (Google GSoC 2014; EmailValidator, TimeISOValidator) -@author Tomas Zigo (LayersListValidator, -PlacementValidator) +@author Stepan Turek (ManageSettingsWidget - created from + GdalSelect) +@author Matej Krejci (Google GSoC 2014; EmailValidator, + TimeISOValidator) +@author Tomas Zigo (LayersListValidator, PlacementValidator) """ import os diff --git a/gui/wxpython/history/tree.py b/gui/wxpython/history/tree.py index cd67dd5fe90..caaeb8bda86 100644 --- a/gui/wxpython/history/tree.py +++ b/gui/wxpython/history/tree.py @@ -19,6 +19,7 @@ import re import copy +import datetime import wx @@ -31,7 +32,7 @@ split, ) from gui_core.forms import GUI -from core.treemodel import TreeModel, ModuleNode +from core.treemodel import TreeModel, DictFilterNode from gui_core.treeview import CTreeView from gui_core.wrap import Menu @@ -40,6 +41,46 @@ from grass.grassdb import history +# global variable for purposes of sorting "No time info" node +OLD_DATE = datetime.datetime(1950, 1, 1).date() + + +class HistoryBrowserNode(DictFilterNode): + """Node representing item in history browser.""" + + def __init__(self, data=None): + super().__init__(data=data) + + @property + def label(self): + if "day" in self.data.keys(): + return self.dayToLabel(self.data["day"]) + else: + return self.data["name"] + + def dayToLabel(self, day): + """ + Convert day (midnight timestamp) to a day node label. + :param day datetime.date object: midnight of a day. + :return str: Corresponding day label. + """ + current_date = datetime.date.today() + + if day == OLD_DATE: + return _("No time info") + + if day == current_date: + return "{:%B %-d} (today)".format(day) + elif day == current_date - datetime.timedelta(days=1): + return "{:%B %-d} (yesterday)".format(day) + elif day >= (current_date - datetime.timedelta(days=current_date.weekday())): + return "{:%B %-d} (this week)".format(day) + elif day.year == current_date.year: + return "{:%B %-d}".format(day) + else: + return "{:%B %-d, %Y}".format(day) + + class HistoryBrowserTree(CTreeView): """Tree structure visualizing and managing history of executed commands. Uses virtual tree and model defined in core/treemodel.py. @@ -57,7 +98,7 @@ def __init__( | wx.TR_FULL_ROW_HIGHLIGHT, ): """History Browser Tree constructor.""" - self._model = TreeModel(ModuleNode) + self._model = TreeModel(HistoryBrowserNode) self._orig_model = self._model super().__init__(parent=parent, model=self._model, id=wx.ID_ANY, style=style) @@ -65,6 +106,8 @@ def __init__( self.parent = parent self.infoPanel = infoPanel + self._resetSelectVariables() + self._initHistoryModel() self.showNotification = Signal("HistoryBrowserTree.showNotification") @@ -72,43 +115,34 @@ def __init__( self._giface.currentMapsetChanged.connect(self.UpdateHistoryModelFromScratch) self._giface.entryToHistoryAdded.connect( - lambda entry: self.AppendNodeToHistoryModel(entry) + lambda entry: self.InsertCommand(entry) ) self._giface.entryInHistoryUpdated.connect( - lambda entry: self.UpdateNodeInHistoryModel(entry) + lambda entry: self.UpdateCommand(entry) ) self.SetToolTip(_("Double-click to open the tool")) self.selectionChanged.connect(self.OnItemSelected) - self.itemActivated.connect(lambda node: self.Run(node)) + self.itemActivated.connect(self.OnDoubleClick) self.contextMenu.connect(self.OnRightClick) - def _initHistoryModel(self): - """Fill tree history model based on the current history log.""" - try: - history_path = history.get_current_mapset_gui_history_path() - content_list = history.read(history_path) - except (OSError, ValueError) as e: - GError(str(e)) - - for data in content_list: - self._model.AppendNode( - parent=self._model.root, - label=data["command"].strip(), - data=data, + def _sortDays(self): + """Sort day nodes from earliest to oldest.""" + if self._model.root.children: + self._model.root.children.sort( + key=lambda node: node.data["day"], reverse=True ) - self._refreshTree() def _refreshTree(self): """Refresh tree models""" + self._sortDays() self.SetModel(copy.deepcopy(self._model)) self._orig_model = self._model - def _getSelectedNode(self): - selection = self.GetSelected() - if not selection: - return None - return selection[0] + def _resetSelectVariables(self): + """Reset variables related to item selection.""" + self.selected_day = [] + self.selected_command = [] def _confirmDialog(self, question, title): """Confirm dialog""" @@ -117,7 +151,7 @@ def _confirmDialog(self, question, title): dlg.Destroy() return res - def _popupMenuLayer(self): + def _popupMenuCommand(self): """Create popup menu for commands""" menu = Menu() @@ -128,15 +162,173 @@ def _popupMenuLayer(self): self.PopupMenu(menu) menu.Destroy() + def _popupMenuEmpty(self): + """Create empty popup when multiple different types of items are selected""" + menu = Menu() + item = wx.MenuItem(menu, wx.ID_ANY, _("No available options")) + menu.AppendItem(item) + item.Enable(False) + self.PopupMenu(menu) + menu.Destroy() + + def _timestampToDay(self, timestamp=None): + """ + Convert timestamp to datetime.date object with time set to midnight. + :param str timestamp: Timestamp as a string in ISO format. + :return datetime.date day_midnight: midnight of a day. + """ + if not timestamp: + return OLD_DATE + + timestamp_datetime = datetime.datetime.fromisoformat(timestamp) + day_midnight = datetime.datetime( + timestamp_datetime.year, timestamp_datetime.month, timestamp_datetime.day + ).date() + + return day_midnight + + def _initHistoryModel(self): + """Fill tree history model based on the current history log.""" + content_list = self.ReadFromHistory() + + for entry in content_list: + timestamp = None + if entry["command_info"]: + # Find day node for entries with command info + timestamp = entry["command_info"].get("timestamp") + if timestamp: + day = self._model.SearchNodes( + parent=self._model.root, + day=self._timestampToDay(timestamp), + type="day", + ) + else: + # Find day node prepared for entries without any command info + day = self._model.SearchNodes( + parent=self._model.root, + day=self._timestampToDay(), + type="day", + ) + + if day: + day = day[0] + else: + # Create time period node if not found + if not entry["command_info"]: + # Prepare it for entries without command info + day = self._model.AppendNode( + parent=self._model.root, + data=dict(type="day", day=self._timestampToDay()), + ) + else: + day = self._model.AppendNode( + parent=self._model.root, + data=dict( + type="day", + day=self._timestampToDay( + entry["command_info"]["timestamp"] + ), + ), + ) + + # Determine status and create command node + status = ( + entry["command_info"].get("status") + if entry.get("command_info") + and entry["command_info"].get("status") is not None + else "unknown" + ) + + # Add command to time period node + self._model.AppendNode( + parent=day, + data=dict( + type="command", + name=entry["command"].strip(), + timestamp=timestamp if timestamp else None, + status=status, + ), + ) + + # Refresh the tree view + self._refreshTree() + + def _getIndexFromFile(self, command_node): + """Get index of command node in the corresponding history log file.""" + if not command_node.data["timestamp"]: + return self._model.GetIndexOfNode(command_node)[1] + else: + return history.filter( + json_data=self.ReadFromHistory(), + command=command_node.data["name"], + timestamp=command_node.data["timestamp"], + ) + + def ReadFromHistory(self): + """Read content of command history log. + It is a wrapper which considers GError. + """ + try: + history_path = history.get_current_mapset_gui_history_path() + content_list = history.read(history_path) + except (OSError, ValueError) as e: + GError(str(e)) + return content_list + + def RemoveEntryFromHistory(self, index): + """Remove entry from command history log. + It is a wrapper which considers GError. + + :param int index: index of the entry which should be removed + """ + try: + history_path = history.get_current_mapset_gui_history_path() + history.remove_entry(history_path, index) + except (OSError, ValueError) as e: + GError(str(e)) + + def GetCommandInfo(self, index): + """Get command info for the given command index. + It is a wrapper which considers GError. + + :param int index: index of the command + """ + command_info = {} + try: + history_path = history.get_current_mapset_gui_history_path() + command_info = history.read(history_path)[index]["command_info"] + except (OSError, ValueError) as e: + GError(str(e)) + return command_info + + def DefineItems(self, selected): + """Set selected items.""" + self._resetSelectVariables() + for item in selected: + type = item.data["type"] + if type == "command": + self.selected_command.append(item) + self.selected_day.append(item.parent) + elif type == "day": + self.selected_command.append(None) + self.selected_day.append(item) + def Filter(self, text): """Filter history :param str text: text string """ if text: - self._model = self._orig_model.Filtered(key=["command"], value=text) + try: + compiled = re.compile(text) + except re.error: + return + self._model = self._orig_model.Filtered( + method="filtering", name=compiled, type="command" + ) else: self._model = self._orig_model self.RefreshItems() + self.ExpandAll() def UpdateHistoryModelFromScratch(self): """Reload tree history model based on the current history log from scratch.""" @@ -144,110 +336,172 @@ def UpdateHistoryModelFromScratch(self): self._initHistoryModel() self.infoPanel.clearCommandInfo() - def AppendNodeToHistoryModel(self, entry): - """Append node to the model and refresh the tree. + def InsertCommand(self, entry): + """Insert command node to the model and refresh the tree. :param entry dict: entry with 'command' and 'command_info' keys """ - new_node = self._model.AppendNode( - parent=self._model.root, - label=entry["command"].strip(), - data=entry, + # Check if today time period node exists or create it + today = self._timestampToDay(entry["command_info"]["timestamp"]) + today_nodes = self._model.SearchNodes( + parent=self._model.root, day=today, type="day" ) + if not today_nodes: + today_node = self._model.AppendNode( + parent=self._model.root, + data=dict( + type="day", + day=today, + ), + ) + else: + today_node = today_nodes[0] + + # Create the command node under today time period node + command_node = self._model.AppendNode( + parent=today_node, + data=dict( + type="command", + name=entry["command"].strip(), + timestamp=entry["command_info"]["timestamp"], + status=entry["command_info"].get("status", "in process"), + ), + ) + + # Refresh the tree self._refreshTree() - self.Select(new_node) - self.ExpandNode(new_node) + + # Select and expand the newly added command node + self.Select(command_node) + self.ExpandNode(command_node) + + # Show command info in info panel self.infoPanel.showCommandInfo(entry["command_info"]) - def UpdateNodeInHistoryModel(self, entry): + def UpdateCommand(self, entry): """Update last node in the model and refresh the tree. :param entry dict: entry with 'command' and 'command_info' keys """ + # Get node of last command + today = self._timestampToDay(entry["command_info"]["timestamp"]) + today_node = self._model.SearchNodes( + parent=self._model.root, day=today, type="day" + )[0] + command_nodes = self._model.SearchNodes(parent=today_node, type="command") + last_node = command_nodes[-1] + # Remove last node - index = [self._model.GetLeafCount(self._model.root) - 1] - tree_node = self._model.GetNodeByIndex(index) - self._model.RemoveNode(tree_node) + self._model.RemoveNode(last_node) - # Add new node to the model - self.AppendNodeToHistoryModel(entry) + # Add new command node to the model + self.InsertCommand(entry) def Run(self, node=None): """Parse selected history command into list and launch module dialog.""" - node = node or self._getSelectedNode() - if node: - command = node.data["command"] - lst = re.split(r"\s+", command) - if ( - globalvar.ignoredCmdPattern - and re.compile(globalvar.ignoredCmdPattern).search(command) - and "--help" not in command - and "--ui" not in command - ): - self.runIgnoredCmdPattern.emit(cmd=lst) - self.runIgnoredCmdPattern.emit(cmd=split(command)) - return - if re.compile(r"^r[3]?\.mapcalc").search(command): - command = parse_mapcalc_cmd(command) - command = replace_module_cmd_special_flags(command) - lst = split(command) - try: - GUI(parent=self, giface=self._giface).ParseCommand(lst) - except GException as e: - GError( - parent=self, - message=str(e), - caption=_("Cannot be parsed into command"), - showTraceback=False, - ) + if not node: + node = self.GetSelected() + self.DefineItems(node) + + if not self.selected_command: + return + + selected_command = self.selected_command[0] + command = selected_command.data["name"] + + lst = re.split(r"\s+", command) + if ( + globalvar.ignoredCmdPattern + and re.compile(globalvar.ignoredCmdPattern).search(command) + and "--help" not in command + and "--ui" not in command + ): + self.runIgnoredCmdPattern.emit(cmd=lst) + self.runIgnoredCmdPattern.emit(cmd=split(command)) + return + if re.compile(r"^r[3]?\.mapcalc").search(command): + command = parse_mapcalc_cmd(command) + command = replace_module_cmd_special_flags(command) + lst = split(command) + try: + GUI(parent=self, giface=self._giface).ParseCommand(lst) + except GException as e: + GError( + parent=self, + message=str(e), + caption=_("Cannot be parsed into command"), + showTraceback=False, + ) - def RemoveEntryFromHistory(self, index): - """Remove entry from command history log. + def OnRemoveCmd(self, event): + """Remove cmd from the history file""" + self.DefineItems(self.GetSelected()) + if not self.selected_command: + return - :param int index: index of the entry which should be removed - """ - try: - history_path = history.get_current_mapset_gui_history_path() - history.remove_entry(history_path, index) - except (OSError, ValueError) as e: - GError(str(e)) + selected_command = self.selected_command[0] + selected_day = self.selected_day[0] + command = selected_command.data["name"] - def GetCommandInfo(self, index): - """Get command info for the given command index. + # Confirm deletion with user + question = _("Do you really want to remove <{}> command?").format(command) + if self._confirmDialog(question, title=_("Remove command")) != wx.ID_YES: + return - :param int index: index of the command - """ - command_info = {} - try: - history_path = history.get_current_mapset_gui_history_path() - command_info = history.read(history_path)[index]["command_info"] - except (OSError, ValueError) as e: - GError(str(e)) - return command_info + self.showNotification.emit(message=_("Removing <{}>").format(command)) - def OnRemoveCmd(self, event): - """Remove cmd from the history file""" - tree_node = self._getSelectedNode() - cmd = tree_node.data["command"] - question = _("Do you really want to remove <{}> command?").format(cmd) - if self._confirmDialog(question, title=_("Remove command")) == wx.ID_YES: - self.showNotification.emit(message=_("Removing <{}>").format(cmd)) - tree_index = self._model.GetIndexOfNode(tree_node)[0] - self.RemoveEntryFromHistory(tree_index) - self.infoPanel.clearCommandInfo() - self._giface.entryFromHistoryRemoved.emit(index=tree_index) - self._model.RemoveNode(tree_node) - self._refreshTree() - self.showNotification.emit(message=_("<{}> removed").format(cmd)) + # Find the index of the selected command in history file + history_index = self._getIndexFromFile(selected_command) + + # Remove the entry from history + self.RemoveEntryFromHistory(history_index) + self.infoPanel.clearCommandInfo() + self._giface.entryFromHistoryRemoved.emit(index=history_index) + self._model.RemoveNode(selected_command) + + # Check if the time period node should also be removed + selected_day = selected_command.parent + if selected_day and len(selected_day.children) == 0: + self._model.RemoveNode(selected_day) + + self._refreshTree() + self.showNotification.emit(message=_("<{}> removed").format(command)) def OnItemSelected(self, node): - """Item selected""" - command = node.data["command"] - self.showNotification.emit(message=command) - tree_index = self._model.GetIndexOfNode(node)[0] - command_info = self.GetCommandInfo(tree_index) + """Handle item selection in the tree view.""" + self.DefineItems([node]) + if not self.selected_command[0]: + return + + selected_command = self.selected_command[0] + self.showNotification.emit(message=selected_command.data["name"]) + + # Find the index of the selected command in history file + history_index = self._getIndexFromFile(selected_command) + + # Show command info in info panel + command_info = self.GetCommandInfo(history_index) self.infoPanel.showCommandInfo(command_info) def OnRightClick(self, node): - """Display popup menu""" - self._popupMenuLayer() + """Display popup menu.""" + self.DefineItems([node]) + if self.selected_command[0]: + self._popupMenuCommand() + else: + self._popupMenuEmpty() + + def OnDoubleClick(self, node): + """Double click on item/node. + + Launch module dialog if node is a command otherwise + expand/collapse node. + """ + self.DefineItems([node]) + if self.selected_command[0]: + self.Run(node) + else: + if self.IsNodeExpanded(node): + self.CollapseNode(node, recursive=False) + else: + self.ExpandNode(node, recursive=False) diff --git a/gui/wxpython/iclass/dialogs.py b/gui/wxpython/iclass/dialogs.py index fb799e27057..48537c10548 100644 --- a/gui/wxpython/iclass/dialogs.py +++ b/gui/wxpython/iclass/dialogs.py @@ -19,6 +19,7 @@ @author Vaclav Petras @author Anna Kratochvilova """ + import os import wx @@ -179,9 +180,9 @@ def GetSelectedGroup(self): return self.groupSelect.GetValue().split("@")[0] def GetGroupBandsErr(self, parent): - """Get list of raster bands which are in the soubgroup of group with both having same name. - If the group does not exists or it does not contain any bands in subgoup with same name, - error dialog is shown. + """Get list of raster bands which are in the subgroup of group with both + having same name. If the group does not exist, or it does not contain any bands + in subgroup with same name, error dialog is shown. """ gr, s = self.GetData() @@ -219,7 +220,8 @@ def GetGroupBandsErr(self, parent): return bands def GetGroupBands(self, group, subgroup): - """Get list of raster bands which are in the soubgroup of group with both having same name.""" + """Get list of raster bands which are in the subgroup of group with both having + same name.""" kwargs = {} if subgroup: @@ -383,7 +385,8 @@ class CategoryListCtrl(ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.TextEdi def __init__(self, parent, mapwindow, stats_data, id=wx.ID_ANY): """ :param parent: gui parent - :param mapwindow: mapwindow instance with iclass toolbar and remove raster method + :param mapwindow: mapwindow instance with iclass toolbar and remove raster + method :param stats_data: StatisticsData instance (defined in statistics.py) :param id: wx id """ diff --git a/gui/wxpython/iclass/frame.py b/gui/wxpython/iclass/frame.py index 9a53317694c..f041f84e892 100644 --- a/gui/wxpython/iclass/frame.py +++ b/gui/wxpython/iclass/frame.py @@ -94,7 +94,8 @@ def __init__( """ :param parent: (no parent is expected) :param title: window title - :param toolbars: dictionary of active toolbars (default value represents all toolbars) + :param toolbars: dictionary of active toolbars (default value represents all + toolbars) :param size: default size """ DoubleMapPanel.__init__( @@ -1445,7 +1446,8 @@ def AddLayer(self, name, alias=None, resultsLayer=False): """Adds layer to Map and update toolbar :param str name: layer (raster) name - :param str resultsLayer: True if layer is temp. raster showing the results of computation + :param str resultsLayer: True if layer is temp. raster showing the results of + computation """ if resultsLayer and name in [ layer.GetName() for layer in self.map.GetListOfLayers(name=name) diff --git a/gui/wxpython/icons/grass_icons.py b/gui/wxpython/icons/grass_icons.py index 2c13429d9ec..e4cd9b55ed7 100644 --- a/gui/wxpython/icons/grass_icons.py +++ b/gui/wxpython/icons/grass_icons.py @@ -3,6 +3,7 @@ http://robert.szczepanek.pl/icons.php https://svn.osgeo.org/osgeo/graphics/toolbar-icons/24x24/ """ + __author__ = "Robert Szczepanek" import os diff --git a/gui/wxpython/image2target/g.gui.image2target.py b/gui/wxpython/image2target/g.gui.image2target.py index 706a0e6a133..d78ff78ae95 100755 --- a/gui/wxpython/image2target/g.gui.image2target.py +++ b/gui/wxpython/image2target/g.gui.image2target.py @@ -129,43 +129,45 @@ def main(): else: os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo" - # if options['source_location']: - # src_loc = options['source_location'] + # if options["source_location"]: + # src_loc = options["source_location"] # else: # gscript.fatal(_("No georeferenced source location provided")) - # if options['source_mapset']: - # src_mpt = options['source_mapset'] + # if options["source_mapset"]: + # src_mpt = options["source_mapset"] # else: # gscript.fatal(_("No georeferenced source mapset provided")) - # if options['source_group']: - # src_grp = options['source_group'] + # if options["source_group"]: + # src_grp = options["source_group"] # else: # gscript.fatal(_("Please provide a source group name to process")) # if options['source_image']: - # src_ras = options['source_image'] + # src_ras = options["source_image"] # else: # gscript.fatal(_("Please provide a source image map name to process")) - # if options['target_image']: - # tgt_ras = options['target_image'] + # if options["target_image"]: + # tgt_ras = options["target_image"] # else: # gscript.fatal(_("No georeferenced target map provided")) - # if options['camera']: - # camera = options['camera'] + # if options["camera"]: + # camera = options["camera"] # else: - # gscript.fatal(_("Please provide a camera name (generated by i.ortho.camera)")) + # gscript.fatal(_( + # "Please provide a camera name (generated by i.ortho.camera)" + # )) - # if options['order']: - # order = options['order'] + # if options["order"]: + # order = options["order"] # else: # gscript.fatal(_("Please provive an order value")) - # if options['extension']: - # extension = options['extension'] + # if options["extension"]: + # extension = options["extension"] # else: # gscript.fatal(_("Please provide an output file extension")) diff --git a/gui/wxpython/image2target/ii2t_gis_set.py b/gui/wxpython/image2target/ii2t_gis_set.py index 641ff2671d5..12ee5938849 100644 --- a/gui/wxpython/image2target/ii2t_gis_set.py +++ b/gui/wxpython/image2target/ii2t_gis_set.py @@ -132,7 +132,8 @@ def __init__(self, parent=None, id=wx.ID_ANY, style=wx.DEFAULT_FRAME_STYLE): self.lmessage = StaticText(parent=self.panel) # It is not clear if all wx versions supports color, so try-except. # The color itself may not be correct for all platforms/system settings - # but in http://xoomer.virgilio.it/infinity77/wxPython/Widgets/wx.SystemSettings.html + # but in + # http://xoomer.virgilio.it/infinity77/wxPython/Widgets/wx.SystemSettings.html # there is no 'warning' color. try: self.lmessage.SetForegroundColour(wx.Colour(255, 0, 0)) diff --git a/gui/wxpython/image2target/ii2t_manager.py b/gui/wxpython/image2target/ii2t_manager.py index f15b89d986f..2828a3b0a58 100644 --- a/gui/wxpython/image2target/ii2t_manager.py +++ b/gui/wxpython/image2target/ii2t_manager.py @@ -112,27 +112,40 @@ class GCPWizard: Start wizard here and finish wizard here """ - # def __init__(self, parent, giface, srcloc, srcmpt, srcgrp, srcras, tgtras, camera, order, extension): - # global maptype - # global src_map - # global tgt_map - # maptype = 'raster' - # rendertype = 'raster' - # self.parent = parent # GMFrame - # self._giface = giface - # self.srcloc = srcloc - # self.srcmpt = srcmpt - # self.group = srcgrp - # self.src_map = srcras - # self.tgt_map = tgtras - # self.camera = camera - # self.order = int(order) - # self.extension = extension - # self.src_maps = self.src_map - # # location for xy map to georectify - # self.newlocation = self.srcloc - # # mapset for xy map to georectify - # self.newmapset = self.srcmpt + # def __init__( + # self, + # parent, + # giface, + # srcloc, + # srcmpt, + # srcgrp, + # srcras, + # tgtras, + # camera, + # order, + # extension, + # ): + # global maptype + # global src_map + # global tgt_map + # maptype = "raster" + # rendertype = "raster" + # self.parent = parent # GMFrame + # self._giface = giface + # self.srcloc = srcloc + # self.srcmpt = srcmpt + # self.group = srcgrp + # self.src_map = srcras + # self.tgt_map = tgtras + # self.camera = camera + # self.order = int(order) + # self.extension = extension + # self.src_maps = self.src_map + # # location for xy map to georectify + # self.newlocation = self.srcloc + # # mapset for xy map to georectify + # self.newmapset = self.srcmpt + def __init__(self, parent, giface): self.parent = parent # GMFrame self._giface = giface @@ -1552,7 +1565,7 @@ def SaveGCPs(self, event): f.write("#\tsource\t\t\ttarget\t\t\tstatus\n") f.write("#\teast\tnorth\theight\teast\tnorth\theight\t(1=ok, 0=ignore)\n") f.write( - "#---------------------------- --------------------------- ---------------\n" + "#---------------------------- --------------------------- ---------------\n" # noqa: E501 ) for index in range(self.list.GetItemCount()): @@ -1707,7 +1720,8 @@ def ReloadGCPs(self, event): targetMapWin.UpdateMap(render=False, renderVector=False) def OnFocus(self, event): - # TODO: it is here just to remove old or obsolete beavior of base class gcp/MapPanel? + # TODO: it is here just to remove old or obsolete beavior of base class + # gcp/MapPanel? # self.grwiz.SwitchEnv('source') pass @@ -1962,16 +1976,19 @@ def OnGROrder(self, event): if self.gr_order == 1: minNumOfItems = 3 - # self.SetStatusText(_('Insufficient points, 3+ points needed for 1st order')) + # self.SetStatusText(_( + # "Insufficient points, 3+ points needed for 1st order")) elif self.gr_order == 2: minNumOfItems = 6 diff = 6 - numOfItems - # self.SetStatusText(_('Insufficient points, 6+ points needed for 2nd order')) + # self.SetStatusText(_( + # "Insufficient points, 6+ points needed for 2nd order")) elif self.gr_order == 3: minNumOfItems = 10 - # self.SetStatusText(_('Insufficient points, 10+ points needed for 3rd order')) + # self.SetStatusText(_( + # "Insufficient points, 10+ points needed for 3rd order")) for i in range(minNumOfItems - numOfItems): self.AddGCP(None) @@ -2907,7 +2924,8 @@ def __init__( btnSave.Bind(wx.EVT_BUTTON, self.OnSave) btnSave.SetToolTip( _( - "Apply and save changes to user settings file (default for next sessions)" + "Apply and save changes to user settings file (default for next " + "sessions)" ) ) btnClose.Bind(wx.EVT_BUTTON, self.OnClose) diff --git a/gui/wxpython/image2target/ii2t_statusbar.py b/gui/wxpython/image2target/ii2t_statusbar.py index 1d10ad0b9b4..1424f7f4846 100644 --- a/gui/wxpython/image2target/ii2t_statusbar.py +++ b/gui/wxpython/image2target/ii2t_statusbar.py @@ -16,7 +16,6 @@ @author Anna Kratochvilova (statusbar refactoring) """ - import wx from core.gcmd import GMessage diff --git a/gui/wxpython/iscatt/controllers.py b/gui/wxpython/iscatt/controllers.py index d3602d9124f..d823dfb6e1a 100644 --- a/gui/wxpython/iscatt/controllers.py +++ b/gui/wxpython/iscatt/controllers.py @@ -19,6 +19,7 @@ @author Stepan Turek (mentor: Martin Landa) """ + from copy import deepcopy import wx @@ -232,8 +233,8 @@ def AddScattPlot(self): "Interactive Scatter Plot Tool can not be used.\n" "Number of cells (rows*cols) <%d> in current region" "is higher than maximum limit <%d>.\n\n" - "You can reduce number of cells in current region using command." - % (ncells, MAX_NCELLS) + "You can reduce number of cells in current region using " + " command." % (ncells, MAX_NCELLS) ), ) ) diff --git a/gui/wxpython/iscatt/dialogs.py b/gui/wxpython/iscatt/dialogs.py index 20787867f04..5fad1990875 100644 --- a/gui/wxpython/iscatt/dialogs.py +++ b/gui/wxpython/iscatt/dialogs.py @@ -406,7 +406,8 @@ def __init__( self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave) self.btnSave.SetToolTip( _( - "Apply and save changes to user settings file (default for next sessions)" + "Apply and save changes to user settings file (default for next " + "sessions)" ) ) self.btnClose.Bind(wx.EVT_BUTTON, self.OnClose) diff --git a/gui/wxpython/iscatt/frame.py b/gui/wxpython/iscatt/frame.py index 242731ef182..9ff5a6ceac6 100644 --- a/gui/wxpython/iscatt/frame.py +++ b/gui/wxpython/iscatt/frame.py @@ -18,7 +18,6 @@ @author Stepan Turek (mentor: Martin Landa) """ - import os import wx diff --git a/gui/wxpython/iscatt/iscatt_core.py b/gui/wxpython/iscatt/iscatt_core.py index d97cdb84a56..1c5b2887edb 100644 --- a/gui/wxpython/iscatt/iscatt_core.py +++ b/gui/wxpython/iscatt/iscatt_core.py @@ -17,6 +17,7 @@ @author Stepan Turek (mentor: Martin Landa) """ + import os import numpy as np diff --git a/gui/wxpython/iscatt/plots.py b/gui/wxpython/iscatt/plots.py index be036ffd7b9..a955250db10 100644 --- a/gui/wxpython/iscatt/plots.py +++ b/gui/wxpython/iscatt/plots.py @@ -15,6 +15,7 @@ @author Stepan Turek (mentor: Martin Landa) """ + import wx import numpy as np from math import ceil @@ -516,27 +517,37 @@ def MergeImg(cats_order, scatts, styles, rend_dt, output_queue): MergeArrays(merged_img, rend_dt[cat_id]["dt"], styles[cat_id]["opacity"]) """ - #c_img_a = np.memmap(grass.tempfile(), dtype="uint16", mode='w+', shape = shape) - c_img_a = colored_cat.astype('uint16')[:,:,3] * styles[cat_id]['opacity'] - - #TODO apply strides and there will be no need for loop - #b = as_strided(a, strides=(0, a.strides[3], a.strides[3], a.strides[3]), shape=(3, a.shape[0], a.shape[1])) - - for i in range(3): - merged_img[:,:,i] = (merged_img[:,:,i] * (255 - c_img_a) + colored_cat[:,:,i] * c_img_a) / 255; - merged_img[:,:,3] = (merged_img[:,:,3] * (255 - c_img_a) + 255 * c_img_a) / 255; - - del c_img_a - """ - + # c_img_a = np.memmap( + # grass.tempfile(), dtype="uint16", mode="w+", shape=shape + # ) + c_img_a = colored_cat.astype("uint16")[:, :, 3] * styles[cat_id]["opacity"] + + # TODO apply strides and there will be no need for loop + # b = as_strided( + # a, + # strides=(0, a.strides[3], a.strides[3], a.strides[3]), + # shape=(3, a.shape[0], a.shape[1]), + # ) + + for i in range(3): + merged_img[:, :, i] = ( + merged_img[:, :, i] * (255 - c_img_a) + + colored_cat[:, :, i] * c_img_a + ) / 255 + merged_img[:, :, 3] = ( + merged_img[:, :, 3] * (255 - c_img_a) + 255 * c_img_a + ) / 255 + + del c_img_a + """ _rendDtMemmapsToFiles(rend_dt) merged_img = {"dt": merged_img.filename, "sh": merged_img.shape} output_queue.put((merged_img, full_extend, rend_dt)) -# _rendDtMemmapsToFiles and _rendDtFilesToMemmaps are workarounds for older numpy versions, -# where memmap objects are not pickable +# _rendDtMemmapsToFiles and _rendDtFilesToMemmaps are workarounds for older numpy +# versions, where memmap objects are not pickable def _rendDtMemmapsToFiles(rend_dt): @@ -629,7 +640,8 @@ class PolygonDrawer: def __init__(self, ax, pol, empty_pol): if pol.figure is None: raise RuntimeError( - "You must first add the polygon to a figure or canvas before defining the interactor" + "You must first add the polygon to a figure or canvas before defining " + "the interactor" ) self.ax = ax self.canvas = pol.figure.canvas diff --git a/gui/wxpython/iscatt/toolbars.py b/gui/wxpython/iscatt/toolbars.py index 47d799e1961..30d9869f861 100644 --- a/gui/wxpython/iscatt/toolbars.py +++ b/gui/wxpython/iscatt/toolbars.py @@ -13,6 +13,7 @@ @author Stepan Turek (mentor: Martin Landa) """ + import wx from icons.icon import MetaIcon @@ -68,7 +69,8 @@ def _toolbarData(self): "zoomExtent": MetaIcon( img="zoom-extent", label=_( - "Zoom to scatter plot data extend mode (click on scatter plot for zooming to extend)" + "Zoom to scatter plot data extend mode (click on scatter plot for " + "zooming to extend)" ), ), "cats_mgr": MetaIcon( diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 2f863103424..c24ee04ab8e 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -595,8 +595,8 @@ def CanCloseDisplay(askIfSaveWorkspace): ) mapdisplay.starting3dMode.connect( - lambda firstTime, mapDisplayPage=self.currentPage: self._onMapDisplayStarting3dMode( - mapDisplayPage + lambda firstTime, mapDisplayPage=self.currentPage: ( + self._onMapDisplayStarting3dMode(mapDisplayPage) ) ) mapdisplay.starting3dMode.connect(self.AddNvizTools) @@ -2129,8 +2129,13 @@ def OnAddRasterNum(self, event): dlg.Destroy() # region = tree.GetMap().GetCurrentRegion() - # if region['cells'] > 10000: - # GMessage(message = "Cell values can only be displayed for regions of < 10,000 cells.", parent = self) + # if region["cells"] > 10000: + # GMessage( + # message=( + # "Cell values can only be displayed for regions of < 10,000 cells." + # ), + # parent=self, + # ) self.GetLayerTree().AddLayer("rastnum") def OnAddCommand(self, event): diff --git a/gui/wxpython/lmgr/giface.py b/gui/wxpython/lmgr/giface.py index 7a2cce9223a..1c347d35a0f 100644 --- a/gui/wxpython/lmgr/giface.py +++ b/gui/wxpython/lmgr/giface.py @@ -198,10 +198,12 @@ def __init__(self, lmgr): # Signal for communicating something in current grassdb has changed. # Parameters: # action: required, is one of 'new', 'rename', 'delete' - # element: required, can be one of 'grassdb', 'location', 'mapset', 'raster', 'vector' and 'raster_3d' + # element: required, can be one of 'grassdb', 'location', 'mapset', 'raster', + # 'vector' and 'raster_3d' # grassdb: path to grass db, required # location: location name, required - # mapset: mapset name, required when element is 'mapset', 'raster', 'vector' or 'raster_3d' + # mapset: mapset name, required when element is 'mapset', 'raster', + # 'vector' or 'raster_3d' # map: map name, required when element is 'raster', 'vector' or 'raster_3d' # newname: new name (of mapset, map), required with action='rename' self.grassdbChanged = Signal("LayerManagerGrassInterface.grassdbChanged") diff --git a/gui/wxpython/lmgr/layertree.py b/gui/wxpython/lmgr/layertree.py index 23f2c7d92c4..03ae921b2ec 100644 --- a/gui/wxpython/lmgr/layertree.py +++ b/gui/wxpython/lmgr/layertree.py @@ -710,29 +710,40 @@ def OnLayerContextMenu(self, event): # removed from layer tree # if digitToolbar: # background vector map - # self.popupMenu.Append(self.popupID['bgmap'], - # text = _("Use as background vector map for digitizer"), - # kind = wx.ITEM_CHECK) - # self.Bind(wx.EVT_MENU, self.OnSetBgMap, id = self.popupID['bgmap']) - # if UserSettings.Get(group = 'vdigit', key = 'bgmap', subkey = 'value', - # internal = True) == layer.GetName(): - # self.popupMenu.Check(self.popupID['bgmap'], True) + # self.popupMenu.Append( + # self.popupID["bgmap"], + # text=_("Use as background vector map for digitizer"), + # kind=wx.ITEM_CHECK, + # ) + # self.Bind(wx.EVT_MENU, self.OnSetBgMap, id = self.popupID["bgmap"]) + # if ( + # UserSettings.Get( + # group="vdigit", key="bgmap", subkey="value", internal=True + # ) + # == layer.GetName() + # ): + # self.popupMenu.Check(self.popupID["bgmap"], True) self.popupMenu.Append(self.popupID["topo"], _("Rebuild topology")) self.Bind(wx.EVT_MENU, self.OnTopology, id=self.popupID["topo"]) # determine format - # if layer and layer.GetType() == 'vector': - # if 'info' not in self.GetLayerInfo(self.layer_selected): - # info = grass.parse_command('v.info', - # flags = 'e', - # map = layer.GetName()) - # self.SetLayerInfo(self.layer_selected, key = 'info', value = info) - # info = self.GetLayerInfo(self.layer_selected, key = 'info') - # if info and info['format'] != 'native' and \ - # info['format'].split(',')[1] == 'PostgreSQL': - # self.popupMenu.Append(self.popupID['sql'], text = _("SQL Spatial Query")) - # self.Bind(wx.EVT_MENU, self.OnSqlQuery, id = self.popupID['sql']) + # if layer and layer.GetType() == "vector": + # if "info" not in self.GetLayerInfo(self.layer_selected): + # info = grass.parse_command( + # "v.info", flags="e", map=layer.GetName() + # ) + # self.SetLayerInfo(self.layer_selected, key="info", value=info) + # info = self.GetLayerInfo(self.layer_selected, key="info") + # if ( + # info + # and info["format"] != "native" + # and info["format"].split(",")[1] == "PostgreSQL" + # ): + # self.popupMenu.Append( + # self.popupID["sql"], text=_("SQL Spatial Query") + # ) + # self.Bind(wx.EVT_MENU, self.OnSqlQuery, id=self.popupID["sql"]) if layer.GetMapset() != currentMapset: # only vector map in current mapset can be edited @@ -1858,6 +1869,8 @@ def OnLayerChecked(self, event): if vselect: vselect.Reset() + self.AdjustMyScrollbars() + def OnCmdChanged(self, event): """Change command string""" ctrl = event.GetEventObject().GetId() diff --git a/gui/wxpython/location_wizard/dialogs.py b/gui/wxpython/location_wizard/dialogs.py index aaa0b4f1112..8c48d75cf18 100644 --- a/gui/wxpython/location_wizard/dialogs.py +++ b/gui/wxpython/location_wizard/dialogs.py @@ -17,6 +17,7 @@ @author Jachym Cepicky @author Martin Landa """ + import os import wx @@ -238,10 +239,12 @@ def MakeSettings3DPaneContent(self, pane): self.ttbres = TextCtrl( parent=pane, id=wx.ID_ANY, value=str(self.tbres), size=(150, -1) ) - # self.tnsres3 = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.nsres3), - # size = (150, -1)) - # self.tewres3 = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.ewres3), - # size = (150, -1)) + # self.tnsres3 = wx.TextCtrl( + # parent=pane, id=wx.ID_ANY, value=str(self.nsres3), size=(150, -1) + # ) + # self.tewres3 = wx.TextCtrl( + # parent=pane, id=wx.ID_ANY, value=str(self.ewres3), size=(150, -1) + # ) # labels self.ldepth = StaticText(parent=pane, label=_("Depth: %d") % self.depth) @@ -279,20 +282,30 @@ def MakeSettings3DPaneContent(self, pane): ) # res - # gridSizer.Add(item = wx.StaticText(parent = pane, label = _("3D N-S resolution")), - # flag = wx.ALIGN_CENTER | - # wx.LEFT | wx.RIGHT | wx.TOP, border = 5, - # pos = (2, 1)) - # gridSizer.Add(item = self.tnsres3, - # flag = wx.ALIGN_CENTER_HORIZONTAL | - # wx.ALL, border = 5, pos = (3, 1)) - # gridSizer.Add(item = wx.StaticText(parent = pane, label = _("3D E-W resolution")), - # flag = wx.ALIGN_CENTER | - # wx.LEFT | wx.RIGHT | wx.TOP, border = 5, - # pos = (2, 3)) - # gridSizer.Add(item = self.tewres3, - # flag = wx.ALIGN_CENTER_HORIZONTAL | - # wx.ALL, border = 5, pos = (3, 3)) + # gridSizer.Add( + # item=wx.StaticText(parent=pane, label=_("3D N-S resolution")), + # flag=wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.TOP, + # border=5, + # pos=(2, 1), + # ) + # gridSizer.Add( + # item=self.tnsres3, + # flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, + # border=5, + # pos=(3, 1), + # ) + # gridSizer.Add( + # item=wx.StaticText(parent=pane, label=_("3D E-W resolution")), + # flag=wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.TOP, + # border=5, + # pos=(2, 3), + # ) + # gridSizer.Add( + # item=self.tewres3, + # flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, + # border=5, + # pos=(3, 3), + # ) # rows/cols/cells gridSizer.Add( @@ -526,10 +539,10 @@ def OnValue(self, event): self.top = float(event.GetString()) elif event.GetId() == self.tbottom.GetId(): self.bottom = float(event.GetString()) - # elif event.GetId() == self.tnsres3.GetId(): - # self.nsres3 = float(event.GetString()) - # elif event.GetId() == self.tewres3.GetId(): - # self.ewres3 = float(event.GetString()) + # elif event.GetId() == self.tnsres3.GetId(): + # self.nsres3 = float(event.GetString()) + # elif event.GetId() == self.tewres3.GetId(): + # self.ewres3 = float(event.GetString()) elif event.GetId() == self.ttbres.GetId(): self.tbres = float(event.GetString()) diff --git a/gui/wxpython/location_wizard/wizard.py b/gui/wxpython/location_wizard/wizard.py index 4127d5047d4..4f3a2924847 100644 --- a/gui/wxpython/location_wizard/wizard.py +++ b/gui/wxpython/location_wizard/wizard.py @@ -33,6 +33,7 @@ @author Martin Landa @author Hamish Bowman (planetary ellipsoids) """ + import os import locale import functools diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index 9701a296d10..3f005defc18 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -738,6 +738,20 @@ def BuildPanes(self): wx.CallAfter(self.datacatalog.LoadItems) + single_win_panes_layout_pos_enabled = UserSettings.Get( + group="general", + key="singleWinPanesLayoutPos", + subkey="enabled", + ) + + single_win_panes_layout_pos = UserSettings.Get( + group="general", + key="singleWinPanesLayoutPos", + subkey="pos", + ) + if single_win_panes_layout_pos_enabled and single_win_panes_layout_pos: + self._auimgr.LoadPerspective(single_win_panes_layout_pos) + self._auimgr.Update() def BindEvents(self): @@ -1029,9 +1043,9 @@ def _renamePageNoEvent(self, pgnum_dict, is_docked, text): ) def _closePageNoEvent(self, pgnum_dict, is_docked): - """If map display is docked, close page and destroy map display without generating - layer notebook page closing event. If map display is undocked, close only - layer notebook page, not map notebook page. + """If map display is docked, close page and destroy map display without + generating layer notebook page closing event. If map display is undocked, + close only layer notebook page, not map notebook page. :param dict pgnum_dict: dict "layers" key represent map display notebook layers tree page index and diff --git a/gui/wxpython/mapdisp/frame.py b/gui/wxpython/mapdisp/frame.py index 6e10937ec6d..c9aeb6f07db 100644 --- a/gui/wxpython/mapdisp/frame.py +++ b/gui/wxpython/mapdisp/frame.py @@ -1237,7 +1237,8 @@ def OnMeasureArea(self, event): def _onMeasure(self, controller): """Starts measurement mode. - :param controller: measurement class (MeasureDistanceController, MeasureAreaController) + :param controller: measurement class (MeasureDistanceController, + MeasureAreaController) """ self.measureController = controller(self._giface, mapWindow=self.GetMapWindow()) # assure that the mode is ended and lines are cleared whenever other @@ -1303,8 +1304,8 @@ def OnScatterplot(self, event): win.CentreOnParent() win.Show() - # Open raster select dialog to make sure that at least 2 rasters (and the desired rasters) - # are selected to be plotted + # Open raster select dialog to make sure that at least 2 rasters (and the + # desired rasters) are selected to be plotted win.OnSelectRaster(None) def OnHistogram(self, event): diff --git a/gui/wxpython/mapdisp/main.py b/gui/wxpython/mapdisp/main.py index 6b6256a915a..9a26378eb1e 100644 --- a/gui/wxpython/mapdisp/main.py +++ b/gui/wxpython/mapdisp/main.py @@ -25,7 +25,7 @@ @author Martin Landa @author Vaclav Petras (MapPanelBase) @author Anna Kratochvilova (MapPanelBase) -""" +""" # noqa: E501 import os import sys @@ -227,7 +227,8 @@ def GetLayersFromCmdFile(self): if layersOrder[i] == -1: layersOrder[i] = next_layer next_layer += 1 - # layer must be put higher in render order (same cmd was insered more times) + # layer must be put higher in render order (same cmd was + # insered more times) # TODO delete rendurant cmds from cmd file? else: for j, l_order in enumerate(layersOrder): diff --git a/gui/wxpython/mapdisp/statusbar.py b/gui/wxpython/mapdisp/statusbar.py index fb8bb4d6528..43211341147 100644 --- a/gui/wxpython/mapdisp/statusbar.py +++ b/gui/wxpython/mapdisp/statusbar.py @@ -53,10 +53,10 @@ class SbManager: Statusbar manager manages items added by AddStatusbarItem method. Provides progress bar (SbProgress). - Items with position 0 are shown according to selection in Map Display settings dialog. - Only one item of the same class is supposed to be in statusbar. - Manager user have to create statusbar on his own, add items to manager - and call Update method to show particular widgets. + Items with position 0 are shown according to selection in Map Display settings + dialog. Only one item of the same class is supposed to be in statusbar. Manager + user have to create statusbar on his own, add items to manager and call Update + method to show particular widgets. User settings (group = 'display', key = 'statusbarMode', subkey = 'selection') are taken into account. @@ -286,7 +286,8 @@ def SetProgress(self, range, value, text): self.statusbar.SetStatusText(text) def OnContextMenu(self, event): - """Popup context menu enabling to choose a widget that will be shown in statusbar.""" + """Popup context menu enabling to choose a widget that will be shown in + statusbar.""" def setSbItemProperty(idx): self.mapFrame.mapWindowProperties.sbItem = idx @@ -381,7 +382,8 @@ def _update(self, longHelp): self.mapFrame.StatusbarEnableLongHelp(longHelp) def Update(self): - """Called when statusbar action is activated (e.g. through Map Display settings).""" + """Called when statusbar action is activated (e.g. through Map Display + settings).""" self._update(longHelp=False) @@ -533,7 +535,8 @@ def ReprojectENToMap(self, e, n, useDefinedProjection): :param e,n: coordinate (for DMS string, else float or string) :param useDefinedProjection: projection defined by user in settings dialog - @throws SbException if useDefinedProjection is True and projection is not defined in UserSettings + @throws SbException if useDefinedProjection is True and projection is not + defined in UserSettings """ if useDefinedProjection: settings = UserSettings.Get( @@ -788,7 +791,8 @@ def ReprojectENFromMap(self, e, n, useDefinedProjection, precision, format): :param e,n: coordinate - @throws SbException if useDefinedProjection is True and projection is not defined in UserSettings + @throws SbException if useDefinedProjection is True and projection is not + defined in UserSettings """ if useDefinedProjection: settings = UserSettings.Get( @@ -867,7 +871,8 @@ def ReprojectRegionFromMap(self, region, useDefinedProjection, precision, format """Reproject region values .. todo:: - reorganize this method to remove code useful only for derived class SbCompRegionExtent + reorganize this method to remove code useful only for derived class + SbCompRegionExtent """ if useDefinedProjection: settings = UserSettings.Get( diff --git a/gui/wxpython/mapdisp/test_mapdisp.py b/gui/wxpython/mapdisp/test_mapdisp.py index 5fb13857a4e..71a1a81f985 100755 --- a/gui/wxpython/mapdisp/test_mapdisp.py +++ b/gui/wxpython/mapdisp/test_mapdisp.py @@ -161,8 +161,10 @@ def testMapDisplay(self, giface, map_): from mapdisp.frame import MapFrame # known issues (should be similar with d.mon): - # * opening map in digitizer ends with: vdigit/toolbars.py:723: 'selection' referenced before assignment - # * nviz start fails (closes window? segfaults?) after mapdisp/frame.py:306: 'NoneType' object has no attribute 'GetLayerNotebook' + # * opening map in digitizer ends with: vdigit/toolbars.py:723: 'selection' + # referenced before assignment + # * nviz start fails (closes window? segfaults?) after mapdisp/frame.py:306: + # 'NoneType' object has no attribute 'GetLayerNotebook' frame = MapFrame( parent=None, title=_("Map display test"), giface=giface, Map=map_ ) diff --git a/gui/wxpython/mapdisp/toolbars.py b/gui/wxpython/mapdisp/toolbars.py index 3da61d60398..3589c7fd5de 100644 --- a/gui/wxpython/mapdisp/toolbars.py +++ b/gui/wxpython/mapdisp/toolbars.py @@ -120,7 +120,8 @@ def __init__(self, parent, toolSwitcher, giface): self._giface.WriteWarning(_("Reason: %s") % errorMsg) self._giface.WriteLog( _( - "Note that the wxGUI's vector digitizer is disabled in this installation. " + "Note that the wxGUI's vector digitizer is disabled in this " + "installation." "Please keep an eye out for updated versions of GRASS. " 'In the meantime you can use "v.edit" for non-interactive editing ' "from the Develop vector map menu." diff --git a/gui/wxpython/mapwin/base.py b/gui/wxpython/mapwin/base.py index 6e179b6aa00..3a27713dfd9 100644 --- a/gui/wxpython/mapwin/base.py +++ b/gui/wxpython/mapwin/base.py @@ -255,8 +255,9 @@ def OnButton(self, event): # current map display's map window # expects LayerManager to be the parent self.mapwin = self.parent.GetLayerTree().GetMapDisplay().GetWindow() - if self.mapwin.RegisterEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction, - 'cross'): + if self.mapwin.RegisterEventHandler( + wx.EVT_LEFT_DOWN, self.OnMouseAction, "cross" + ): self.parent.GetLayerTree().GetMapDisplay().Raise() else: # handle that you cannot get coordinates @@ -264,8 +265,10 @@ def OnButton(self, event): def OnMouseAction(self, event): # get real world coordinates of mouse click coor = self.mapwin.Pixel2Cell(event.GetPositionTuple()[:]) - self.text.SetLabel('Coor: ' + str(coor)) - self.mapwin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction) + self.text.SetLabel("Coor: " + str(coor)) + self.mapwin.UnregisterMouseEventHandler( + wx.EVT_LEFT_DOWN, self.OnMouseAction + ) event.Skip() @@ -390,7 +393,8 @@ def OnMotion(self, event): def GetLastEN(self): """Returns last coordinates of mouse cursor. - @deprecated This method is deprecated. Use Signal with coordinates as parameters. + @deprecated This method is deprecated. Use Signal with coordinates as + parameters. :func:`OnMotion` """ diff --git a/gui/wxpython/mapwin/buffered.py b/gui/wxpython/mapwin/buffered.py index 6f7f918af3e..23989ae865f 100644 --- a/gui/wxpython/mapwin/buffered.py +++ b/gui/wxpython/mapwin/buffered.py @@ -866,7 +866,8 @@ def UpdateMap(self, render=True, renderVector=True, delay=0.0): giface :param render: re-render map composition - :param renderVector: re-render vector map layer enabled for editing (used for digitizer) + :param renderVector: re-render vector map layer enabled for editing (used for + digitizer) :param delay: defines time threshold in seconds for postponing rendering to merge more update requests. @@ -2254,7 +2255,8 @@ def RegisterGraphicsToDraw( is not defined DrawCross method is used for type "point", DrawLines method for type "line", DrawRectangle for "rectangle". - :param mapCoords: True if map coordinates should be set by user, otherwise pixels + :param mapCoords: True if map coordinates should be set by user, otherwise + pixels :return: reference to GraphicsSet, which was added. """ diff --git a/gui/wxpython/mapwin/decorations.py b/gui/wxpython/mapwin/decorations.py index 5ead9c5f0e7..9e2051a435d 100644 --- a/gui/wxpython/mapwin/decorations.py +++ b/gui/wxpython/mapwin/decorations.py @@ -32,7 +32,6 @@ class OverlayController: - """Base class for decorations (barscale, legend) controller.""" def __init__(self, renderer, giface): @@ -300,7 +299,8 @@ def GetPlacement(self, screensize): for param in self._cmd: if not param.startswith("at"): continue - # if the at= is the default, we will move the legend from the center to bottom left + # if the at= is the default, we will move the legend from the center to + # bottom left if param == self._defaultAt: b, t, l, r = 5, 50, 7, 10 else: diff --git a/gui/wxpython/mapwin/graphics.py b/gui/wxpython/mapwin/graphics.py index 1522cf9f4dd..0bc94bae6d2 100644 --- a/gui/wxpython/mapwin/graphics.py +++ b/gui/wxpython/mapwin/graphics.py @@ -15,7 +15,6 @@ @author Stepan Turek (handlers support, GraphicsSet) """ - from copy import copy import wx diff --git a/gui/wxpython/modules/colorrules.py b/gui/wxpython/modules/colorrules.py index 96606fb0653..626c0ea93d5 100644 --- a/gui/wxpython/modules/colorrules.py +++ b/gui/wxpython/modules/colorrules.py @@ -1403,8 +1403,8 @@ def AddTemporaryColumn(self, type): :param type: type of column (e.g. vachar(11))""" if not self.CheckMapset(): return - # because more than one dialog with the same map can be opened we must test column name and - # create another one + # because more than one dialog with the same map can be opened we must test + # column name and create another one while ( self.properties["tmpColumn"] in self.dbInfo.GetTableDesc(self.properties["table"]).keys() diff --git a/gui/wxpython/modules/import_export.py b/gui/wxpython/modules/import_export.py index 97a646037ed..da082feb68d 100644 --- a/gui/wxpython/modules/import_export.py +++ b/gui/wxpython/modules/import_export.py @@ -959,7 +959,8 @@ def __init__( parent=self.panel, id=wx.ID_ANY, label=_( - "Projection of following layers do not match with projection of current location. " + "Projection of following layers do not match with projection of " + "current location. " ), ) diff --git a/gui/wxpython/nviz/mapwindow.py b/gui/wxpython/nviz/mapwindow.py index 1c291e1068b..52548983f58 100644 --- a/gui/wxpython/nviz/mapwindow.py +++ b/gui/wxpython/nviz/mapwindow.py @@ -2066,18 +2066,18 @@ def UpdateVolumeProperties(self, id, data, isosurfId=None): if ( data["draw"]["shading"]["isosurface"]["value"] < 0 ): # need to calculate - mode = data["draw"]["shading"]["isosurface"][ - "value" - ] = self.nvizDefault.GetDrawMode( - shade=data["draw"]["shading"]["isosurface"], string=False + mode = data["draw"]["shading"]["isosurface"]["value"] = ( + self.nvizDefault.GetDrawMode( + shade=data["draw"]["shading"]["isosurface"], string=False + ) ) self._display.SetIsosurfaceMode(id, mode) else: if data["draw"]["shading"]["slice"]["value"] < 0: # need to calculate - mode = data["draw"]["shading"]["slice"][ - "value" - ] = self.nvizDefault.GetDrawMode( - shade=data["draw"]["shading"]["slice"], string=False + mode = data["draw"]["shading"]["slice"]["value"] = ( + self.nvizDefault.GetDrawMode( + shade=data["draw"]["shading"]["slice"], string=False + ) ) self._display.SetSliceMode(id, mode) data["draw"]["shading"].pop("update") @@ -2370,7 +2370,8 @@ def GetLayerId(self, type, name, vsubtyp=None): return -1 def ReloadLayersData(self): - """Delete nviz data of all loaded layers and reload them from current settings""" + """Delete nviz data of all loaded layers and reload them from current + settings""" for item in self.layers: type = self.tree.GetLayerInfo(item, key="type") layer = self.tree.GetLayerInfo(item, key="maplayer") @@ -2504,17 +2505,7 @@ def NvizCmdCommand(self): # vlines # if vectors: - cmdLines = ( - cmdLWidth - ) = ( - cmdLHeight - ) = ( - cmdLColor - ) = ( - cmdLMode - ) = ( - cmdLPos - ) = ( + cmdLines = cmdLWidth = cmdLHeight = cmdLColor = cmdLMode = cmdLPos = ( cmdPoints ) = cmdPWidth = cmdPSize = cmdPColor = cmdPMarker = cmdPPos = cmdPLayer = "" markers = [ diff --git a/gui/wxpython/nviz/tools.py b/gui/wxpython/nviz/tools.py index 09a93de8539..686be2e98ef 100644 --- a/gui/wxpython/nviz/tools.py +++ b/gui/wxpython/nviz/tools.py @@ -200,11 +200,32 @@ def LoadSettings(self): def OnPageChanged(self, event): new = event.GetSelection() - # self.ChangeSelection(new) - # Data, Appearance, Analysis page - if new in (1, 2, 3): - foldpanel = self.GetPage(new).GetChildren()[0] - wx.CallLater(100, self.UpdateScrolling, (foldpanel,)) + pages = { + # Data page + 1: { + "expand": lambda: self._expandFoldPanelBarPanel( + foldPanelBar=self.foldpanelData, + ), + "foldPanelBar": self.foldpanelData, + }, + # Appearance page + 2: { + "expand": lambda: self._expandFoldPanelBarPanel( + foldPanelBar=self.foldpanelAppear, + ), + "foldPanelBar": self.foldpanelAppear, + }, + # Analysis page + 3: { + "expand": lambda: self._expandFoldPanelBarPanel( + foldPanelBar=self.foldpanelAnalysis, + ), + "foldPanelBar": self.foldpanelAnalysis, + }, + } + if new in pages.keys(): + pages[new]["expand"]() + wx.CallAfter(self.UpdateScrolling, (pages[new]["foldPanelBar"],)) def PostViewEvent(self, zExag=False): """Change view settings""" @@ -235,9 +256,54 @@ def UpdateScrolling(self, foldpanels): """Update scrollbars in foldpanel""" for foldpanel in foldpanels: length = foldpanel.GetPanelsLength(collapsed=0, expanded=0) - # virtual width is set to fixed value to suppress GTK warning - foldpanel.GetParent().SetVirtualSize((100, length[2])) - foldpanel.GetParent().Layout() + # Show scrollbars + for panelIdx in range(foldpanel.GetCount()): + # Nested ScrolledPanel widget with horizontal scrollbar + scrolledPanel = ( + foldpanel.GetFoldPanel(panelIdx).GetParent().GetGrandParent() + ) + width = self.GetSize()[0] + if sys.platform in ("darwin", "win32"): + width -= 60 # 60px right margin to show scrollbar + scrolledPanel.SetVirtualSize(width=width, height=length[2]) + scrolledPanel.Layout() + + def _expandFoldPanelBarPanel(self, foldPanelBar, expandFoldPanelBarIdx=0): + """ + Expand FoldPanelBar widget panel + + Fix expanding FoldPanelBar widget panel (fist panel), because using + AddFoldPanel method with collapsed=True param arg cause the expanding + panel to render incorrectly on wxMAC, wxMSW. + + :param obj foldPanelBar: FoldPanelBar widget obj instance + :param int expandFoldpanelbarIdx: FoldPanelBar widget panel index with + default value 0 (first panel) + """ + foldPanelsCount = foldPanelBar.GetCount() + expanded = [] + for panelIdx in range(foldPanelsCount): + foldPanel = foldPanelBar.GetFoldPanel(panelIdx) + expanded.append(foldPanel.IsExpanded()) + if not any(expanded): + foldPanelBar.Expand(foldPanelBar.GetFoldPanel(expandFoldPanelBarIdx)) + + def _resizeScrolledPanel(self, foldPanelBar, scrolledPanel, collapsed, expanded): + """ + Resize FoldPanelBar widget ScrolledPanel to show scrollbars + + :param obj foldPanelBar: FolPanelBar widget obj instance + :param obj scrolledPanel: ScrolledPanel widget obj instance + :param int collapsed: number of collapsed panels of FoldPanelBar + widget + :param int expanded: number of expanded panels of FoldPanelBar + widget + """ + if expanded > 0: + foldPanelBar.Expand(foldPanelBar.GetFoldPanel(0)) + length = foldPanelBar.GetPanelsLength(collapsed, expanded) + scrolledPanel.SetSize(self.GetSize()[0], length[2]) + foldPanelBar.Collapse(foldPanelBar.GetFoldPanel(0)) def _createViewPage(self): """Create view settings page""" @@ -263,7 +329,8 @@ def _createViewPage(self): gridSizer.Add(posSizer, pos=(0, 0)) # perspective - # set initial defaults here (or perhaps in a default values file), not in user settings + # set initial defaults here (or perhaps in a default values file), not in user + # settings # todo: consider setting an absolute max at 360 instead of undefined. # (leave the default max value at pi) tooltip = _( @@ -422,7 +489,8 @@ def _createViewPage(self): top.SetName("top") top.SetToolTip( _( - "Sets the viewer directly over the scene's center position. This top view orients approximately north south." + "Sets the viewer directly over the scene's center position. This top " + "view orients approximately north south." ) ) viewSizer.Add(top, flag=wx.TOP | wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL, border=5) @@ -619,7 +687,8 @@ def _createAnimationPage(self): ) prefixCtrl.SetToolTip( _( - "Generated files names will look like this: prefix_1.ppm, prefix_2.ppm, ..." + "Generated files names will look like this: prefix_1.ppm, " + "prefix_2.ppm, ..." ) ) fileTypeLabel = StaticText(parent=panel, id=wx.ID_ANY, label=_("File format:")) @@ -661,8 +730,9 @@ def _createAnimationPage(self): def _createDataPage(self): """Create data (surface, vector, volume) settings page""" - self.mainPanelData = ScrolledPanel(parent=self) + self.mainPanelData = SP.ScrolledPanel(parent=self) self.mainPanelData.SetupScrolling(scroll_x=False) + self.mainPanelData.AlwaysShowScrollbars(hflag=False) try: # wxpython <= 2.8.10 self.foldpanelData = fpb.FoldPanelBar( parent=self.mainPanelData, @@ -685,7 +755,7 @@ def _createDataPage(self): self.foldpanelData.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption) # # surface page - surfacePanel = self.foldpanelData.AddFoldPanel(_("Surface"), collapsed=False) + surfacePanel = self.foldpanelData.AddFoldPanel(_("Surface"), collapsed=True) self.foldpanelData.AddFoldPanelWindow( surfacePanel, window=self._createSurfacePage(parent=surfacePanel), @@ -729,13 +799,20 @@ def _createDataPage(self): self.mainPanelData.Layout() self.mainPanelData.Fit() + self._resizeScrolledPanel( + foldPanelBar=self.foldpanelData, + scrolledPanel=self.mainPanelData, + collapsed=self.foldpanelData.GetCount() - 1, + expanded=1, + ) + return self.mainPanelData def _createAppearancePage(self): """Create data (surface, vector, volume) settings page""" - self.mainPanelAppear = ScrolledPanel(parent=self) + self.mainPanelAppear = SP.ScrolledPanel(parent=self) self.mainPanelAppear.SetupScrolling(scroll_x=False) - + self.mainPanelAppear.AlwaysShowScrollbars(hflag=False) try: # wxpython <= 2.8.10 self.foldpanelAppear = fpb.FoldPanelBar( parent=self.mainPanelAppear, @@ -757,7 +834,7 @@ def _createAppearancePage(self): self.foldpanelAppear.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption) # light page - lightPanel = self.foldpanelAppear.AddFoldPanel(_("Lighting"), collapsed=False) + lightPanel = self.foldpanelAppear.AddFoldPanel(_("Lighting"), collapsed=True) self.foldpanelAppear.AddFoldPanelWindow( lightPanel, window=self._createLightPage(parent=lightPanel), @@ -789,19 +866,28 @@ def _createAppearancePage(self): self.mainPanelAppear.SetSizer(sizer) self.mainPanelAppear.Layout() self.mainPanelAppear.Fit() + + self._resizeScrolledPanel( + foldPanelBar=self.foldpanelAppear, + scrolledPanel=self.mainPanelAppear, + collapsed=self.foldpanelAppear.GetCount() - 1, + expanded=1, + ) + return self.mainPanelAppear def _createAnalysisPage(self): """Create data analysis (cutting planes, ...) page""" - self.mainPanelAnalysis = ScrolledPanel(parent=self) + self.mainPanelAnalysis = SP.ScrolledPanel(parent=self) self.mainPanelAnalysis.SetupScrolling(scroll_x=False) + self.mainPanelAnalysis.AlwaysShowScrollbars(hflag=False) self.foldpanelAnalysis = fpb.FoldPanelBar( parent=self.mainPanelAnalysis, id=wx.ID_ANY, style=fpb.FPB_SINGLE_FOLD ) self.foldpanelAnalysis.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption) # cutting planes page cplanePanel = self.foldpanelAnalysis.AddFoldPanel( - _("Cutting planes"), collapsed=False + _("Cutting planes"), collapsed=True ) self.foldpanelAnalysis.AddFoldPanelWindow( cplanePanel, @@ -814,6 +900,14 @@ def _createAnalysisPage(self): self.mainPanelAnalysis.SetSizer(sizer) self.mainPanelAnalysis.Layout() self.mainPanelAnalysis.Fit() + + self._resizeScrolledPanel( + foldPanelBar=self.foldpanelAnalysis, + scrolledPanel=self.mainPanelAnalysis, + collapsed=self.foldpanelAnalysis.GetCount() - 1, + expanded=1, + ) + return self.mainPanelAnalysis def _createSurfacePage(self, parent): @@ -1334,7 +1428,8 @@ def _createCPlanePage(self, parent): flag=wx.ALIGN_CENTER_VERTICAL, ) tooltip = _( - "Sets the Z coordinate of the current cutting plane (only meaningful when tilt is not 0)" + "Sets the Z coordinate of the current cutting plane (only meaningful when " + "tilt is not 0)" ) self._createControl( panel, @@ -1377,6 +1472,7 @@ def _createCPlanePage(self, parent): pageSizer.Add(boxSizer, proportion=0, flag=wx.EXPAND) panel.SetSizer(pageSizer) + panel.Layout() panel.Fit() panel.SetupScrolling(scroll_y=False) @@ -1470,6 +1566,7 @@ def _createConstantPage(self, parent): pageSizer.Add(boxSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=3) panel.SetSizer(pageSizer) + panel.Layout() panel.Fit() panel.SetupScrolling(scroll_y=False) @@ -1903,6 +2000,7 @@ def _createVectorPage(self, parent): ) panel.SetSizer(pageSizer) + panel.Layout() panel.Fit() panel.SetupScrolling(scroll_y=False) @@ -2118,6 +2216,7 @@ def _createVolumePage(self, parent): border=3, ) panel.SetSizer(pageSizer) + panel.Layout() panel.Fit() panel.SetupScrolling(scroll_y=False) @@ -2583,7 +2682,8 @@ def OnRecord(self, event): if not anim.IsPaused(): if anim.Exists() and not anim.IsSaved(): msg = _( - "Do you want to record new animation without saving the previous one?" + "Do you want to record new animation without saving the previous " + "one?" ) dlg = wx.MessageDialog( parent=self, @@ -4200,7 +4300,7 @@ def OnVectorPoints(self, event): marker = self.FindWindowById( self.win["vector"]["points"]["marker"] ).GetSelection() - # width = self.FindWindowById(self.win['vector']['points']['width']).GetValue() + # width = self.FindWindowById(self.win['vector']['points']['width']).GetValue() for attrb in ("size", "marker"): data["vector"]["points"][attrb]["update"] = None diff --git a/gui/wxpython/photo2image/ip2i_manager.py b/gui/wxpython/photo2image/ip2i_manager.py index 7af883ccf6a..fc89994607a 100644 --- a/gui/wxpython/photo2image/ip2i_manager.py +++ b/gui/wxpython/photo2image/ip2i_manager.py @@ -22,7 +22,8 @@ @author Original version improved by Martin Landa @author Rewritten by Markus Metz redesign georectfier -> GCP Manage @author Support for GraphicsSet added by Stepan Turek (2012) -@author Yann modified: graphical replacement of i.photo.2image (was in v6 using Vask lib) +@author Yann modified: graphical replacement of i.photo.2image + (was in v6 using Vask lib) """ import os @@ -473,7 +474,7 @@ def __init__( f.write("#\tsource\t\ttarget\t\tstatus\n") f.write("#\teast\tnorth\teast\tnorth\t(1=ok, 0=ignore)\n") f.write( - "#----------------------- ----------------------- ---------------\n" + "#----------------------- ----------------------- ---------------\n" # noqa: E501 ) check = "0" @@ -894,7 +895,7 @@ def SaveGCPs(self, event): f.write("#\tsource\t\ttarget\t\tstatus\n") f.write("#\teast\tnorth\teast\tnorth\t(1=ok, 0=ignore)\n") f.write( - "#----------------------- ----------------------- ---------------\n" + "#----------------------- ----------------------- ---------------\n" # noqa: E501 ) for index in range(self.list.GetItemCount()): @@ -1040,7 +1041,8 @@ def ReloadGCPs(self, event): targetMapWin.UpdateMap(render=False) def OnFocus(self, event): - # TODO: it is here just to remove old or obsolete beavior of base class gcp/MapPanel? + # TODO: it is here just to remove old or obsolete beavior of base class + # gcp/MapPanel? # self.grwiz.SwitchEnv('source') pass @@ -1251,16 +1253,19 @@ def OnGROrder(self, event): if self.gr_order == 1: minNumOfItems = 3 - # self.SetStatusText(_('Insufficient points, 3+ points needed for 1st order')) + # self.SetStatusText(_( + # "Insufficient points, 3+ points needed for 1st order")) elif self.gr_order == 2: minNumOfItems = 6 diff = 6 - numOfItems - # self.SetStatusText(_('Insufficient points, 6+ points needed for 2nd order')) + # self.SetStatusText(_( + # "Insufficient points, 6+ points needed for 2nd order")) elif self.gr_order == 3: minNumOfItems = 10 - # self.SetStatusText(_('Insufficient points, 10+ points needed for 3rd order')) + # self.SetStatusText(_( + # "Insufficient points, 10+ points needed for 3rd order")) for i in range(minNumOfItems - numOfItems): self.AddGCP(None) @@ -2039,7 +2044,8 @@ def __init__( btnSave.Bind(wx.EVT_BUTTON, self.OnSave) btnSave.SetToolTip( _( - "Apply and save changes to user settings file (default for next sessions)" + "Apply and save changes to user settings file (default for next " + "sessions)" ) ) btnClose.Bind(wx.EVT_BUTTON, self.OnClose) diff --git a/gui/wxpython/photo2image/ip2i_statusbar.py b/gui/wxpython/photo2image/ip2i_statusbar.py index c1fcf9a9907..3415906aeee 100644 --- a/gui/wxpython/photo2image/ip2i_statusbar.py +++ b/gui/wxpython/photo2image/ip2i_statusbar.py @@ -16,7 +16,6 @@ @author Anna Kratochvilova (statusbar refactoring) """ - import wx from core.gcmd import GMessage diff --git a/gui/wxpython/psmap/dialogs.py b/gui/wxpython/psmap/dialogs.py index 1e0a7851409..ce10ad3ba96 100644 --- a/gui/wxpython/psmap/dialogs.py +++ b/gui/wxpython/psmap/dialogs.py @@ -436,19 +436,28 @@ def AddExtendedPosition(self, panel, gridBagSizer, dialogDict): def AddFont(self, parent, dialogDict, color=True): parent.font = dict() - ## parent.font['fontLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose font:")) - ## parent.font['fontCtrl'] = wx.FontPickerCtrl(parent, id = wx.ID_ANY) - ## - # parent.font['fontCtrl'].SetSelectedFont( - # wx.FontFromNativeInfoString(dialogDict['font'] + " " + str(dialogDict['fontsize']))) - # parent.font['fontCtrl'].SetMaxPointSize(50) - ## + # parent.font["fontLabel"] = wx.StaticText( + # parent, id=wx.ID_ANY, label=_("Choose font:") + # ) + # parent.font["fontCtrl"] = wx.FontPickerCtrl(parent, id=wx.ID_ANY) + # + # parent.font["fontCtrl"].SetSelectedFont( + # wx.FontFromNativeInfoString( + # dialogDict["font"] + " " + str(dialogDict["fontsize"]) + # ) + # ) + # parent.font["fontCtrl"].SetMaxPointSize(50) + # # if color: - ## parent.font['colorLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose color:")) - ## parent.font['colorCtrl'] = ColourPickerCtrl(parent, id = wx.ID_ANY, style=wx.FNTP_FONTDESC_AS_LABEL) - # parent.font['colorCtrl'].SetColour(dialogDict['color']) - - # parent.font['colorCtrl'].SetColour(convertRGB(dialogDict['color'])) + # parent.font["colorLabel"] = wx.StaticText( + # parent, id=wx.ID_ANY, label=_("Choose color:") + # ) + # parent.font["colorCtrl"] = ColourPickerCtrl( + # parent, id=wx.ID_ANY, style=wx.FNTP_FONTDESC_AS_LABEL + # ) + # parent.font["colorCtrl"].SetColour(dialogDict["color"]) + # + # parent.font["colorCtrl"].SetColour(convertRGB(dialogDict["color"])) parent.font["fontLabel"] = StaticText(parent, id=wx.ID_ANY, label=_("Font:")) parent.font["fontSizeLabel"] = StaticText( @@ -485,13 +494,30 @@ def AddFont(self, parent, dialogDict, color=True): parent.font["colorCtrl"] = ColourPickerCtrl(parent, id=wx.ID_ANY) parent.font["colorCtrl"].SetColour(convertRGB(dialogDict["color"])) - ## parent.font['colorLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Color:")) - # colorChoices = [ 'aqua', 'black', 'blue', 'brown', 'cyan', 'gray', 'green', 'indigo', 'magenta',\ - # 'orange', 'purple', 'red', 'violet', 'white', 'yellow'] - ## parent.colorCtrl = Choice(parent, id = wx.ID_ANY, choices = colorChoices) - # parent.colorCtrl.SetStringSelection(parent.rLegendDict['color']) - ## parent.font['colorCtrl'] = ColourPickerCtrl(parent, id = wx.ID_ANY) - # parent.font['colorCtrl'].SetColour(dialogDict['color']) + # parent.font["colorLabel"] = wx.StaticText( + # parent, id=wx.ID_ANY, label=_("Color:") + # ) + # colorChoices = [ + # "aqua", + # "black", + # "blue", + # "brown", + # "cyan", + # "gray", + # "green", + # "indigo", + # "magenta", + # "orange", + # "purple", + # "red", + # "violet", + # "white", + # "yellow", + # ] + # parent.colorCtrl = Choice(parent, id=wx.ID_ANY, choices=colorChoices) + # parent.colorCtrl.SetStringSelection(parent.rLegendDict["color"]) + # parent.font["colorCtrl"] = ColourPickerCtrl(parent, id=wx.ID_ANY) + # parent.font["colorCtrl"].SetColour(dialogDict["color"]) def OnApply(self, event): ok = self.update() @@ -1257,7 +1283,8 @@ def OnScaleChoice(self, event): self.mapText.SetLabel(self.mapOrRegionText[0]) self.select.SetToolTip( _( - "Region is set to match this map,\nraster or vector map must be added later" + "Region is set to match this map,\nraster or vector map must " + "be added later" ) ) @@ -2082,11 +2109,15 @@ def updateDialog(self): pass -# if 'map' in self.parent.openDialogs: -# if self.parent.openDialogs['map'].mPanel.rasterTypeRadio.GetValue()\ -# and self.parent.openDialogs['map'].mPanel.select.GetValue(): -# if self.parent.openDialogs['map'].mPanel.drawMap.IsChecked(): -# self.rPanel.rasterSelect.SetValue(self.parent.openDialogs['map'].mPanel.select.GetValue()) +# if "map" in self.parent.openDialogs: +# if ( +# self.parent.openDialogs["map"].mPanel.rasterTypeRadio.GetValue() +# and self.parent.openDialogs["map"].mPanel.select.GetValue() +# ): +# if self.parent.openDialogs["map"].mPanel.drawMap.IsChecked(): +# self.rPanel.rasterSelect.SetValue( +# self.parent.openDialogs["map"].mPanel.select.GetValue() +# ) class MainVectorDialog(PsmapDialog): @@ -2941,13 +2972,21 @@ def _StyleLinePanel(self, notebook): styleText = StaticText(panel, id=wx.ID_ANY, label=_("Choose line style:")) penStyles = ["solid", "dashed", "dotted", "dashdotted"] self.styleCombo = PenStyleComboBox(panel, choices=penStyles) - # self.styleCombo = wx.ComboBox(panel, id = wx.ID_ANY, - ## choices = ["solid", "dashed", "dotted", "dashdotted"], - # validator = TCValidator(flag = 'ZERO_AND_ONE_ONLY')) - # self.styleCombo.SetToolTipString(_("It's possible to enter a series of 0's and 1's too. "\ - ## "The first block of repeated zeros or ones represents 'draw', "\ - ## "the second block represents 'blank'. An even number of blocks "\ - # "will repeat the pattern, an odd number of blocks will alternate the pattern.")) + # self.styleCombo = wx.ComboBox( + # panel, + # id=wx.ID_ANY, + # choices=["solid", "dashed", "dotted", "dashdotted"], + # validator=TCValidator(flag="ZERO_AND_ONE_ONLY"), + # ) + # self.styleCombo.SetToolTipString( + # _( + # "It's possible to enter a series of 0's and 1's too. " + # "The first block of repeated zeros or ones represents 'draw', " + # "the second block represents 'blank'. An even number of blocks " + # "will repeat the pattern, an odd number of blocks will alternate " + # "the pattern." + # ) + # ) linecapText = StaticText(panel, id=wx.ID_ANY, label=_("Choose linecap:")) self.linecapChoice = Choice( panel, id=wx.ID_ANY, choices=["butt", "round", "extended_butt"] @@ -3212,9 +3251,9 @@ def update(self): if self.colorColRadio.GetValue(): # this color is taken in case of no record in rgb column self.vPropertiesDict["fcolor"] = "none" - self.vPropertiesDict[ - "rgbcolumn" - ] = self.colorColChoice.GetStringSelection() + self.vPropertiesDict["rgbcolumn"] = ( + self.colorColChoice.GetStringSelection() + ) else: self.vPropertiesDict["fcolor"] = "none" @@ -3238,9 +3277,9 @@ def update(self): if self.colorColRadio.GetValue(): # this color is taken in case of no record in rgb column self.vPropertiesDict["color"] = "none" - self.vPropertiesDict[ - "rgbcolumn" - ] = self.colorColChoice.GetStringSelection() + self.vPropertiesDict["rgbcolumn"] = ( + self.colorColChoice.GetStringSelection() + ) # # size and style # @@ -3258,9 +3297,9 @@ def update(self): self.vPropertiesDict["sizecolumn"] = None self.vPropertiesDict["scale"] = None else: - self.vPropertiesDict[ - "sizecolumn" - ] = self.sizeColChoice.GetStringSelection() + self.vPropertiesDict["sizecolumn"] = ( + self.sizeColChoice.GetStringSelection() + ) self.vPropertiesDict["scale"] = self.scaleSpin.GetValue() self.vPropertiesDict["size"] = None @@ -3273,9 +3312,9 @@ def update(self): if self.rotateRadio.GetValue(): self.vPropertiesDict["rotate"] = self.rotateSpin.GetValue() else: - self.vPropertiesDict[ - "rotatecolumn" - ] = self.rotateColChoice.GetStringSelection() + self.vPropertiesDict["rotatecolumn"] = ( + self.rotateColChoice.GetStringSelection() + ) if self.type == "areas": # pattern @@ -3763,8 +3802,10 @@ def sizePositionFont(self, legendType, parent, mainSizer): ) if legendType == "raster": - ## panel.defaultSize = wx.CheckBox(panel, id = wx.ID_ANY, label = _("Use default size")) - # panel.defaultSize.SetValue(legendDict['defaultSize']) + # panel.defaultSize = wx.CheckBox( + # panel, id=wx.ID_ANY, label=_("Use default size") + # ) + # panel.defaultSize.SetValue(legendDict["defaultSize"]) panel.heightOrColumnsLabel = StaticText( panel, id=wx.ID_ANY, label=_("Height:") @@ -3782,7 +3823,13 @@ def sizePositionFont(self, legendType, parent, mainSizer): ) self.rSizeGBSizer = wx.GridBagSizer(hgap=5, vgap=5) - ## self.rSizeGBSizer.Add(panel.defaultSize, pos = (0,0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0) + # self.rSizeGBSizer.Add( + # panel.defaultSize, + # pos=(0, 0), + # span=(1, 2), + # flag=wx.ALIGN_CENTER_VERTICAL, + # border=0, + # ) self.rSizeGBSizer.Add( width, pos=(0, 0), flag=wx.ALIGN_CENTER_VERTICAL, border=0 ) @@ -3926,7 +3973,8 @@ def sizePositionFont(self, legendType, parent, mainSizer): # some enable/disable methods def OnIsLegend(self, event): - """Enables and disables controls, it depends if raster or vector legend is checked""" + """Enables and disables controls, it depends if raster or vector legend is + checked""" page = self.notebook.GetSelection() if page == 0 or event is None: children = self.panelRaster.GetChildren() @@ -4096,8 +4144,9 @@ def OnSpan(self, event): self.panelVector.spanTextCtrl.Enable(self.panelVector.spanRadio.GetValue()) def OnFont(self, event): - """Changes default width according to fontsize, width [inch] = fontsize[pt]/24""" - ## fontsize = self.panelVector.font['fontCtrl'].GetSelectedFont().GetPointSize() + """Changes default width according to fontsize, + width [inch] = fontsize[pt]/24""" + # fontsize = self.panelVector.font["fontCtrl"].GetSelectedFont().GetPointSize() fontsize = self.panelVector.font["fontSizeCtrl"].GetValue() unit = self.unitConv.findUnit( self.panelVector.units["unitsCtrl"].GetStringSelection() @@ -4928,7 +4977,11 @@ def _scalebarPanel(self): else: bitmap = wx.Bitmap(path) self.sbCombo.Append(item="", bitmap=bitmap, clientData=item[0]) - # self.sbCombo.Append(item = 'simple', bitmap = wx.Bitmap("./images/scalebar-simple.png"), clientData = 's') + # self.sbCombo.Append( + # item="simple", + # bitmap=wx.Bitmap("./images/scalebar-simple.png"), + # clientData="s", + # ) if self.scalebarDict["scalebar"] == "f": self.sbCombo.SetSelection(0) elif self.scalebarDict["scalebar"] == "s": diff --git a/gui/wxpython/psmap/frame.py b/gui/wxpython/psmap/frame.py index 85ccbae0067..ef6bc17f59b 100644 --- a/gui/wxpython/psmap/frame.py +++ b/gui/wxpython/psmap/frame.py @@ -317,7 +317,8 @@ def OnPDFFile(self, event): GMessage( parent=self, message=_( - "Program ps2pdf is not available. Please install it first to create PDF." + "Program ps2pdf is not available. Please install it first to " + "create PDF." ), ) return @@ -505,7 +506,8 @@ def OnCmdDone(self, event): self, title=_("Preview not available"), message=_( - "Preview is not available probably because Ghostscript is not installed or not on PATH." + "Preview is not available probably because Ghostscript is not " + "installed or not on PATH." ), hyperlink="https://www.ghostscript.com/releases/gsdnld.html", hyperlinkLabel=_( @@ -1062,7 +1064,8 @@ def getTextExtent(self, textDict): return (0, 0) def getInitMap(self): - """Create default map frame when no map is selected, needed for coordinates in map units""" + """Create default map frame when no map is selected, needed for coordinates in + map units""" instrFile = grass.tempfile() instrFileFd = open(instrFile, mode="wb") content = self.InstructionFile() @@ -1457,7 +1460,8 @@ def Clear(self): self.SetPage() def CanvasPaperCoordinates(self, rect, canvasToPaper=True): - """Converts canvas (pixel) -> paper (inch) coordinates and size and vice versa""" + """Converts canvas (pixel) -> paper (inch) coordinates and size and + vice versa""" units = UnitConversion(self) @@ -1524,7 +1528,8 @@ def modifyRectangle(self, r): return r def RecalculateEN(self): - """Recalculate east and north for texts (eps, points) after their or map's movement""" + """Recalculate east and north for texts (eps, points) after their or map's + movement""" try: mapId = self.instruction.FindInstructionByType("map").id except AttributeError: @@ -2292,10 +2297,10 @@ def Zoom(self, zoomFactor, view): rot = float(self.instruction[id]["rotate"]) else: rot = 0 - self.instruction[id][ - "rect" - ] = bounds = self.parent.getModifiedTextBounds( - coords[0], coords[1], extent, rot + self.instruction[id]["rect"] = bounds = ( + self.parent.getModifiedTextBounds( + coords[0], coords[1], extent, rot + ) ) self.DrawRotText( pdc=self.pdcObj, @@ -2528,12 +2533,16 @@ def DrawRotText(self, pdc, drawId, textDict, coords, bounds): pdc.BeginDrawing() # border is not redrawn when zoom changes, why? - # if textDict['border'] != 'none' and not rot: - ## units = UnitConversion(self) - # borderWidth = units.convert(value = textDict['width'], - # fromUnit = 'point', toUnit = 'pixel' ) * self.currScale - ## pdc.SetPen(wx.Pen(colour = convertRGB(textDict['border']), width = borderWidth)) - # pdc.DrawRectangle(*bounds) + # if textDict["border"] != "none" and not rot: + # units = UnitConversion(self) + # borderWidth = ( + # units.convert( + # value=textDict["width"], fromUnit="point", toUnit="pixel") + # * self.currScale + # ) + # pdc.SetPen(wx.Pen(colour=convertRGB( + # textDict["border"]), width=borderWidth)) + # pdc.DrawRectangle(*bounds) if background: pdc.SetTextBackground(convertRGB(background)) diff --git a/gui/wxpython/psmap/instructions.py b/gui/wxpython/psmap/instructions.py index 0b36a2ae7ab..c527fe65df0 100644 --- a/gui/wxpython/psmap/instructions.py +++ b/gui/wxpython/psmap/instructions.py @@ -738,7 +738,8 @@ def Read(self, instruction, text, **kwargs): ): GWarning( _( - "Map frame position changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s" + "Map frame position changed, old value: %(old1)s %(old2)s\n" + "new value: %(new1)s %(new2)s" ) % { "old1": maploc[0], @@ -748,7 +749,12 @@ def Read(self, instruction, text, **kwargs): } ) - # instr['rect'] = wx.Rect2D(float(maploc[0]), float(maploc[1]), self.instruction['rect'][2], self.instruction['rect'][3]) + # instr["rect"] = wx.Rect2D( + # float(maploc[0]), + # float(maploc[1]), + # self.instruction["rect"][2], + # self.instruction["rect"][3], + # ) if len(maploc) == 4: if ( abs(self.instruction["rect"].Get()[2] - float(maploc[2])) > 0.5 @@ -756,7 +762,8 @@ def Read(self, instruction, text, **kwargs): ): GWarning( _( - "Map frame size changed, old value: %(old1)s %(old2)s\nnew value: %(new1)s %(new2)s" + "Map frame size changed, old value: %(old1)s %(old2)s\n" + "new value: %(new1)s %(new2)s" ) % { "old1": maploc[2], @@ -799,7 +806,8 @@ def __str__(self): else: instr = string.Template("paper $Format\n").substitute(self.instruction) instr += string.Template( - " left $Left\n right $Right\n bottom $Bottom\n top $Top\n end" + " left $Left\n right $Right\n bottom $Bottom\n top $Top\n" + " end" ).substitute(self.instruction) return instr @@ -829,7 +837,8 @@ def Read(self, instruction, text, **kwargs): except KeyError: GError( _( - "Failed to read instruction %(file)s.\nUnknown format %(for)s" + "Failed to read instruction %(file)s.\n" + "Unknown format %(for)s" ) % {"file": instruction, "for": format} ) diff --git a/gui/wxpython/psmap/utils.py b/gui/wxpython/psmap/utils.py index af68405446f..f7e4cea1ad3 100644 --- a/gui/wxpython/psmap/utils.py +++ b/gui/wxpython/psmap/utils.py @@ -15,6 +15,7 @@ @author Anna Kratochvilova """ + import wx from math import ceil, floor, sin, cos, pi diff --git a/gui/wxpython/rdigit/controller.py b/gui/wxpython/rdigit/controller.py index 26e9f455e68..2e98ca32ccc 100644 --- a/gui/wxpython/rdigit/controller.py +++ b/gui/wxpython/rdigit/controller.py @@ -13,6 +13,7 @@ @author Anna Petrasova """ + import os import tempfile import wx diff --git a/gui/wxpython/rdigit/toolbars.py b/gui/wxpython/rdigit/toolbars.py index ec18102fbdf..277e4c11ff6 100644 --- a/gui/wxpython/rdigit/toolbars.py +++ b/gui/wxpython/rdigit/toolbars.py @@ -83,7 +83,8 @@ def __init__(self, parent, giface, controller, toolSwitcher): self._widthValueChanged() self._widthValue.SetToolTip( _( - "Width of currently digitized line or diameter of a digitized point in map units." + "Width of currently digitized line or diameter of a digitized point " + "in map units." ) ) labelWidth = StaticText(self, label=" %s" % _("Width:")) diff --git a/gui/wxpython/rlisetup/functions.py b/gui/wxpython/rlisetup/functions.py index d77962a97c1..2b9433ea4d6 100644 --- a/gui/wxpython/rlisetup/functions.py +++ b/gui/wxpython/rlisetup/functions.py @@ -3,6 +3,7 @@ @author: lucadelu """ + import wx import os import sys diff --git a/gui/wxpython/startup/guiutils.py b/gui/wxpython/startup/guiutils.py index ca04e52aefc..d94da9f9b16 100644 --- a/gui/wxpython/startup/guiutils.py +++ b/gui/wxpython/startup/guiutils.py @@ -14,7 +14,6 @@ This is for code which depend on something from GUI (wx or wxGUI). """ - import os import wx diff --git a/gui/wxpython/startup/locdownload.py b/gui/wxpython/startup/locdownload.py index 887e38b918b..588d30960d0 100644 --- a/gui/wxpython/startup/locdownload.py +++ b/gui/wxpython/startup/locdownload.py @@ -41,11 +41,11 @@ LOCATIONS = [ { "label": "Complete North Carolina dataset", - "url": "https://grass.osgeo.org/sampledata/north_carolina/nc_spm_08_grass7.tar.gz", + "url": "https://grass.osgeo.org/sampledata/north_carolina/nc_spm_08_grass7.tar.gz", # noqa: E501 }, { "label": "Basic North Carolina dataset", - "url": "https://grass.osgeo.org/sampledata/north_carolina/nc_basic_spm_grass7.tar.gz", + "url": "https://grass.osgeo.org/sampledata/north_carolina/nc_basic_spm_grass7.tar.gz", # noqa: E501 }, { "label": "World dataset in LatLong/WGS84", @@ -57,7 +57,7 @@ }, { "label": "Piemonte, Italy dataset", - "url": "https://grass.osgeo.org/sampledata/grassdata_piemonte_utm32n_wgs84_grass7.tar.gz", + "url": "https://grass.osgeo.org/sampledata/grassdata_piemonte_utm32n_wgs84_grass7.tar.gz", # noqa: E501 }, { "label": "Slovakia 3D precipitation voxel dataset", @@ -137,7 +137,9 @@ def _resize(self, heigth=-1): ) -# based on https://blog.shichao.io/2012/10/04/progress_speed_indicator_for_urlretrieve_in_python.html +# based on +# https://blog.shichao.io/2012/10/04/ +# progress_speed_indicator_for_urlretrieve_in_python.html def reporthook(count, block_size, total_size): global start_time if count == 0: @@ -243,7 +245,8 @@ def __init__(self, parent, database, locations=LOCATIONS): # It is not clear if all wx versions supports color, so try-except. # The color itself may not be correct for all platforms/system settings - # but in http://xoomer.virgilio.it/infinity77/wxPython/Widgets/wx.SystemSettings.html + # but in + # http://xoomer.virgilio.it/infinity77/wxPython/Widgets/wx.SystemSettings.html # there is no 'warning' color. try: self.message.SetForegroundColour(wx.Colour(255, 0, 0)) diff --git a/gui/wxpython/tools/build_modules_xml.py b/gui/wxpython/tools/build_modules_xml.py index 96ec07a7e5b..8dc341d7c75 100644 --- a/gui/wxpython/tools/build_modules_xml.py +++ b/gui/wxpython/tools/build_modules_xml.py @@ -22,7 +22,7 @@ def escapeXML(text): """This is a duplicate of function in core/toolboxes. - >>> escapeXML('<>&') + >>> escapeXML("<>&") '&lt;>&' """ return text.replace("<", "<").replace("&", "&").replace(">", ">") @@ -72,11 +72,11 @@ def parse_modules(fd): def get_module_metadata(name): """ - >>> get_module_metadata('g.region') + >>> get_module_metadata("g.region") ('Manages the boundary definitions for the geographic region.', ['general', 'settings']) - >>> get_module_metadata('m.proj') + >>> get_module_metadata("m.proj") ('Converts coordinates from one projection to another (cs2cs frontend).', ['miscellaneous', 'projection']) - """ + """ # noqa: E501 try: task = gtask.parse_interface(name) except ScriptError as exc: diff --git a/gui/wxpython/tplot/g.gui.tplot.py b/gui/wxpython/tplot/g.gui.tplot.py index ae07e0e4022..1a411dabf31 100755 --- a/gui/wxpython/tplot/g.gui.tplot.py +++ b/gui/wxpython/tplot/g.gui.tplot.py @@ -104,7 +104,7 @@ # %option # % key: size # % type: string -# % label: The size for output image +# % label: Size of output image as width,height in pixels # % description: It works only with output parameter # % required: no # %end diff --git a/gui/wxpython/vdigit/preferences.py b/gui/wxpython/vdigit/preferences.py index b9eb12f38a3..cdd88f6b6d5 100644 --- a/gui/wxpython/vdigit/preferences.py +++ b/gui/wxpython/vdigit/preferences.py @@ -302,7 +302,8 @@ def _createGeneralPage(self, notebook): ) self.selectIn.SetToolTip( _( - "By default are selected all features overlapping selection bounding box " + "By default are selected all features overlapping selection bounding " + "box " ) ) @@ -631,7 +632,8 @@ def _createAttributesPage(self, notebook): check = CheckBox( parent=panel, id=wx.ID_ANY, label=self.geomAttrb[attrb]["label"] ) - # self.deleteRecord.SetValue(UserSettings.Get(group='vdigit', key="delRecord", subkey='enabled')) + # self.deleteRecord.SetValue(UserSettings.Get( + # group='vdigit', key="delRecord", subkey='enabled')) check.Bind(wx.EVT_CHECKBOX, self.OnGeomAttrb) # column (only numeric) column = ColumnSelect(parent=panel, size=(200, -1)) diff --git a/gui/wxpython/vdigit/toolbars.py b/gui/wxpython/vdigit/toolbars.py index 306732e79b4..e1af771c4d8 100644 --- a/gui/wxpython/vdigit/toolbars.py +++ b/gui/wxpython/vdigit/toolbars.py @@ -14,6 +14,7 @@ @author Martin Landa @author Stepan Turek (handlers support) """ + import wx from grass import script as grass @@ -182,7 +183,8 @@ def _toolbarData(self): "deleteLine": MetaIcon( img="line-delete", label=_( - "Delete selected point(s), line(s), boundary(ies) or centroid(s) (Ctrl+D)" + "Delete selected point(s), line(s), boundary(ies) or " + "centroid(s) (Ctrl+D)" ), desc=_("Left: Select; Ctrl+Left: Unselect; Right: Confirm"), ), @@ -211,7 +213,8 @@ def _toolbarData(self): "moveLine": MetaIcon( img="line-move", label=_( - "Move selected point(s), line(s), boundary(ies) or centroid(s) (Ctrl+M)" + "Move selected point(s), line(s), boundary(ies) or " + "centroid(s) (Ctrl+M)" ), desc=_("Left: Select; Ctrl+Left: Unselect; Right: Confirm"), ), diff --git a/gui/wxpython/vdigit/wxdigit.py b/gui/wxpython/vdigit/wxdigit.py index 9cf6005a077..ac95eb32131 100644 --- a/gui/wxpython/vdigit/wxdigit.py +++ b/gui/wxpython/vdigit/wxdigit.py @@ -26,7 +26,6 @@ @author Martin Landa """ - import grass.script.core as grass from grass.pydispatch.signal import Signal @@ -201,7 +200,8 @@ def __init__(self, giface, mapwindow, driver=DisplayDriver): # signals parameter description: # old_bboxs - list of bboxes of boundary features, which covers changed areas # it is bbox of old state (before edit) - # old_areas_cats - list of area categories of boundary features of old state (before edit) + # old_areas_cats - + # list of area categories of boundary features of old state (before edit) # same position in both lists corresponds to same feature # new_bboxs = list of bboxes of created features / after edit @@ -238,7 +238,8 @@ def __del__(self): del self.bgMapInfo def EmitSignals(self, emit): - """Activate/deactivate signals which describes features changes during digitization.""" + """Activate/deactivate signals which describes features changes during + digitization.""" self.emit_signals = emit def CloseBackgroundMap(self): @@ -435,7 +436,8 @@ def _applyChangeset(self, changeset, undo): if Vect_line_alive(self.poMapInfo, line): Debug.msg( 3, - "IVDigit._applyChangeset(): changeset=%d, action=add, line=%d -> deleted", + "IVDigit._applyChangeset(): " + "changeset=%d, action=add, line=%d -> deleted", changeset, line, ) @@ -445,7 +447,8 @@ def _applyChangeset(self, changeset, undo): else: Debug.msg( 3, - "Digit.ApplyChangeset(): changeset=%d, action=add, line=%d dead", + "Digit.ApplyChangeset(): " + "changeset=%d, action=add, line=%d dead", changeset, line, ) @@ -456,7 +459,8 @@ def _applyChangeset(self, changeset, undo): if not Vect_line_alive(self.poMapInfo, line): Debug.msg( 3, - "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d -> added", + "Digit.ApplyChangeset(): " + "changeset=%d, action=delete, line=%d -> added", changeset, line, ) @@ -467,7 +471,8 @@ def _applyChangeset(self, changeset, undo): else: Debug.msg( 3, - "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d alive", + "Digit.ApplyChangeset(): " + "changeset=%d, action=delete, line=%d alive", changeset, line, ) diff --git a/gui/wxpython/vdigit/wxdisplay.py b/gui/wxpython/vdigit/wxdisplay.py index 21f86f3718d..c44859c976b 100644 --- a/gui/wxpython/vdigit/wxdisplay.py +++ b/gui/wxpython/vdigit/wxdisplay.py @@ -17,7 +17,6 @@ @author Martin Landa """ - import locale import os @@ -819,7 +818,8 @@ def SetSelected(self, ids, layer=-1): self.selected["cats"] = ids self.selected["ids"] = list() # cidx is not up-to-date - # Vect_cidx_find_all(self.poMapInfo, layer, GV_POINTS | GV_LINES, lid, ilist) + # Vect_cidx_find_all(self.poMapInfo, + # layer, GV_POINTS | GV_LINES, lid, ilist) nlines = Vect_get_num_lines(self.poMapInfo) for line in range(1, nlines + 1): if not Vect_line_alive(self.poMapInfo, line): diff --git a/gui/wxpython/vnet/dialogs.py b/gui/wxpython/vnet/dialogs.py index 2d6ed76e44a..03b48b698bb 100644 --- a/gui/wxpython/vnet/dialogs.py +++ b/gui/wxpython/vnet/dialogs.py @@ -100,8 +100,8 @@ def __init__( self.mapWin = giface.GetMapWindow() self.giface = giface - # contains current analysis result (do not have to be last one, when history is browsed), - # it is instance of VectMap class + # contains current analysis result (do not have to be last one, when history + # is browsed), it is instance of VectMap class self.tmp_result = None self.defIsecTurnsHndlrReg = False @@ -388,7 +388,8 @@ def _createParametersPage(self): ["arc_layer", "Arc layer number or name:", LayerSelect], ["node_layer", "Node layer number or name:", LayerSelect], # ['turn_layer', "Layer with turntable:", LayerSelect], - # ['turn_cat_layer', "Layer with unique categories for turntable:", LayerSelect], + # ['turn_cat_layer', + # "Layer with unique categories for turntable:", LayerSelect], ["arc_column", "", ColumnSelect], ["arc_backward_column", "", ColumnSelect], ["node_column", "", ColumnSelect], @@ -737,7 +738,8 @@ def TtbCreated(self): self.stBar.RemoveStatusItem("ttb") def OnVectSel(self, event): - """When vector map is selected it populates other comboboxes in Parameters tab (layer selects, columns selects)""" + """When vector map is selected it populates other comboboxes in Parameters + tab (layer selects, columns selects)""" if self.vnet_mgr.IsSnappingActive(): # TODO should be in vnet_mgr self.vnet_mgr.Snapping(activate=True) @@ -798,7 +800,8 @@ def _updateParamsTab(self, params, flags): self.inputData[k].SetValue(params[k]) def OnALayerSel(self, event): - """When arc layer from vector map is selected, populates corespondent columns selects""" + """When arc layer from vector map is selected, populates corespondent columns + selects""" self.inputData["arc_column"].InsertColumns( vector=self.inputData["input"].GetValue(), layer=self.inputData["arc_layer"].GetValue(), @@ -813,7 +816,8 @@ def OnALayerSel(self, event): self._setInputData() def OnNLayerSel(self, event): - """When node layer from vector map is selected, populates corespondent column select""" + """When node layer from vector map is selected, populates corespondent column + select""" if self.vnet_mgr.IsSnappingActive(): self.vnet_mgr.Snapping(activate=True) @@ -898,7 +902,10 @@ def OnDefIsecTurnCost(self, event): # TODO move to vnet mgr? if ["turn_layer", "turn_cat_layer"] in err_params: GMessage( parent=self, - message="Please choose existing turntable layer and unique categories layer in Parameters tab.", + message=( + "Please choose existing turntable layer and unique " + "categories layer in Parameters tab." + ), ) cat = GetNearestNodeCat( @@ -1322,7 +1329,8 @@ def __init__( self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave) self.btnSave.SetToolTip( _( - "Apply and save changes to user settings file (default for next sessions)" + "Apply and save changes to user settings file " + "(default for next sessions)" ) ) self.btnClose.Bind(wx.EVT_BUTTON, self.OnClose) @@ -1619,7 +1627,8 @@ def _doSelLayout(self, title, sel, btn=None): return selSizer def InputSel(self): - """When vector map is selected it populates other comboboxes in Parameters tab (layer selects, columns selects)""" + """When vector map is selected it populates other comboboxes in Parameters tab + (layer selects, columns selects)""" vectMapName, mapSet = self._parseMapStr(self.inputData["input"].GetValue()) vectorMap = vectMapName + "@" + mapSet @@ -1711,7 +1720,8 @@ def _layout(self): class VnetStatusbar(wx.StatusBar): - """Extends wx.StatusBar class with functionality to show multiple messages with the highest priority""" + """Extends wx.StatusBar class with functionality to show multiple messages with + the highest priority""" def __init__(self, parent, style, id=wx.ID_ANY, **kwargs): wx.StatusBar.__init__(self, parent, id, style, **kwargs) diff --git a/gui/wxpython/vnet/toolbars.py b/gui/wxpython/vnet/toolbars.py index bb0a1aacdd5..5f80e50cd9d 100644 --- a/gui/wxpython/vnet/toolbars.py +++ b/gui/wxpython/vnet/toolbars.py @@ -85,7 +85,7 @@ def _toolbarData(self): icons["pointDelete"], self.OnDeletePoint, ), - (None,) # , + (None,), # , # ('isec_turn_edit', icons['isec_turn_edit'], # self.dialog.OnDefIsecTurnCosts, # wx.ITEM_CHECK), diff --git a/gui/wxpython/vnet/vnet_core.py b/gui/wxpython/vnet/vnet_core.py index ea5e329e319..ff0e2fd7fe6 100644 --- a/gui/wxpython/vnet/vnet_core.py +++ b/gui/wxpython/vnet/vnet_core.py @@ -127,7 +127,8 @@ def RunAnalysis(self): return False # for case there is some map with same name - # (when analysis does not produce any map, this map would have been shown as result) + # (when analysis does not produce any map, this map would have been shown + # as result) RunCommand( "g.remove", flags="f", @@ -604,10 +605,11 @@ def _updateTtbByGlobalCosts(self, vectMapName, tlayer): # if angle < from_angle: # angle = math.pi * 2 + angle - where = " WHERE (((angle < {0}) AND ({2} + angle >= {0} AND {2} + angle < {1})) OR \ - ((angle >= {0}) AND (angle >= {0} AND angle < {1}))) AND cost==0.0 ".format( - str(from_angle), str(to_angle), str(math.pi * 2) - ) + where = ( + " WHERE (((angle < {0}) AND ({2} + angle >= {0} AND {2} + angle < {1}))" + " OR ((angle >= {0}) AND (angle >= {0} AND angle < {1})))" + " AND cost==0.0 " + ).format(str(from_angle), str(to_angle), str(math.pi * 2)) stm = ("UPDATE %s SET cost=%f " % (table, cost)) + where + ";\n" sqlFile_f.write(stm) @@ -753,7 +755,8 @@ def _runAnDone(self, event): def _setInputParams(self, analysis, params, flags): """Return list of chosen values (vector map, layers). - The list items are in form to be used in command for analysis e.g. 'arc_layer=1'. + The list items are in form to be used in command for analysis + e.g. 'arc_layer=1'. """ inParams = [] diff --git a/gui/wxpython/vnet/vnet_data.py b/gui/wxpython/vnet/vnet_data.py index 946e31975e8..edf17a7fc8b 100644 --- a/gui/wxpython/vnet/vnet_data.py +++ b/gui/wxpython/vnet/vnet_data.py @@ -22,6 +22,7 @@ @author Lukas Bocan (turn costs support) @author Eliska Kyzlikova (turn costs support) """ + import os import math from copy import deepcopy @@ -142,7 +143,8 @@ def GetLayerStyle(self): def InputsErrorMsgs( self, msg, analysis, params, flags, inv_params, relevant_params ): - """Checks input data in Parameters tab and shows messages if some value is not valid + """Checks input data in Parameters tab and shows messages if some value is + not valid :param str msg: message added to start of message string :return: True if checked inputs are OK @@ -192,7 +194,8 @@ def InputsErrorMsgs( for col in ["arc_column", "arc_backward_column", "node_column"]: if params[col] and col in inv_params and col in relevant_params: errColStr += _( - "Chosen column '%s' does not exist in attribute table of layer '%s' of vector map '%s'.\n" + "Chosen column '%s' does not exist in attribute table of layer " + "'%s' of vector map '%s'.\n" ) % (params[col], params[layer], params["input"]) if errColStr: @@ -407,7 +410,8 @@ def ParametersChanged(self, method, kwargs): self._vnetPathUpdateUsePoints(None) def _updateTypeCol(self): - """Rename category values when module is changed. Expample: Start point -> Sink point""" + """Rename category values when module is changed. Example: Start point + -> Sink point""" colValues = [""] analysis, valid = self.an_params.GetParam("analysis") anParamsCats = self.an_data[analysis]["cmdParams"]["cats"] @@ -736,7 +740,8 @@ def __init__(self): }, "resultProps": { "singleColor": None, - "dbMgr": True, # TODO delete this property, this information can be get from result + "dbMgr": True, # TODO delete this property, this information can + # be get from result }, "turns_support": True, }, @@ -1083,7 +1088,8 @@ def GetLastModified(self): class History: - """Class which reads and saves history data (based on gui.core.settings Settings class file save/load) + """Class which reads and saves history data (based on gui.core.settings Settings + class file save/load) .. todo:: Maybe it could be useful for other GRASS wxGUI tools. diff --git a/gui/wxpython/vnet/widgets.py b/gui/wxpython/vnet/widgets.py index ba0d35048bf..44e88cf3df0 100644 --- a/gui/wxpython/vnet/widgets.py +++ b/gui/wxpython/vnet/widgets.py @@ -15,7 +15,8 @@ @author Original author Michael Barton @author Original version improved by Martin Landa @author Rewritten by Markus Metz redesign georectfier -> GCP Manage -@author Stepan Turek (Created PointsList from GCPList) (GSoC 2012, mentor: Martin Landa) +@author Stepan Turek (Created PointsList from GCPList) + (GSoC 2012, mentor: Martin Landa) """ import os @@ -64,13 +65,13 @@ def __init__( Structure of list item must be this: -1. item: column name -2. item: column label - -3. item: If column is editable by user, it must contain convert function to convert - inserted string to it's type for sorting. Use None for not editable - columns. Values for insertion can be in list. This allows insert - just values in the list. - -4. item: Default value for column cell. Value should be given in it's type - in order to sorting would work properly. If 3. item is list, it must be index - of some item in the list. + -3. item: If column is editable by user, it must contain convert + function to convert inserted string to it's type for sorting. + Use None for not editable columns. Values for insertion can be + in list. This allows insert just values in the list. + -4. item: Default value for column cell. Value should be given in it's + type in order to sorting would work properly. If 3. item is + list, it must be index of some item in the list. Example of cols parameter: column name, column label, convert function, default val @@ -82,8 +83,9 @@ def __init__( ['N', _('target N'), float, 0.0], ['F_Err', _('Forward error'), None, 0], ['B_Err', _(Backward error'), None, 0] - ['type', _('type'), [_(""), _("Start point"), _("End point")], 0] # Select from 3 choices ("Start point", "End point"), - # Choice with index 0 ("") is default. + # Select from 3 choices ("Start point", "End point"), + # Choice with index 0 ("") is default. + ['type', _('type'), [_(""), _("Start point"), _("End point")], 0] ] @endcode """ @@ -281,7 +283,8 @@ def _findIndex(self, key): return -1 def ChangeColEditable(self, colName, colType): - """Change 3. item in constructor parameter cols (see the class constructor hint)""" + """Change 3. item in constructor parameter cols (see the class constructor + hint)""" colNum = self._getColumnNum(colName) iColEd = self.dataTypes["colEditable"] self.colsData[colNum][iColEd] = colType @@ -504,7 +507,8 @@ def ShowColumn(self, colName, pos): :param colName: name of column :type colName: str - :param pos: zero based index of position among showed columns (including added 'use' column) + :param pos: zero based index of position among showed columns (including added + 'use' column) :return: True if column was shown :return: False if position is not valid or column is not hidden diff --git a/gui/wxpython/web_services/cap_interface.py b/gui/wxpython/web_services/cap_interface.py index 44de7b6056a..d73cdb5bc84 100644 --- a/gui/wxpython/web_services/cap_interface.py +++ b/gui/wxpython/web_services/cap_interface.py @@ -1,7 +1,8 @@ """ @package web_services.cap_interface -@brief Provides common interface for GUI web_services.widgets to capabilities data of web services. +@brief Provides common interface for GUI web_services.widgets to capabilities data of + web services. List of classes: - cap_interface::CapabilitiesBase diff --git a/gui/wxpython/web_services/dialogs.py b/gui/wxpython/web_services/dialogs.py index f6f76103585..7ad21f824a8 100644 --- a/gui/wxpython/web_services/dialogs.py +++ b/gui/wxpython/web_services/dialogs.py @@ -414,7 +414,8 @@ def OnPanelCapParsed(self, error_msg): def _getConnectedWS(self): """ - :return: list of found web services on server (identified as keys in self.ws_panels) + :return: list of found web services on server (identified as keys in + self.ws_panels) """ conn_ws = [] for ws, data in self.ws_panels.items(): @@ -424,7 +425,8 @@ def _getConnectedWS(self): return conn_ws def UpdateDialogAfterConnection(self): - """Update dialog after all web service panels downloaded and parsed capabilities data.""" + """Update dialog after all web service panels downloaded and parsed + capabilities data.""" avail_ws = {} conn_ws = self._getConnectedWS() diff --git a/gui/wxpython/web_services/widgets.py b/gui/wxpython/web_services/widgets.py index e1cf5e84dd8..1a4b4c5501f 100644 --- a/gui/wxpython/web_services/widgets.py +++ b/gui/wxpython/web_services/widgets.py @@ -558,8 +558,8 @@ def _parseCapFile(self, cap_file): self.cap = self.ws_drvs[self.ws]["cap_parser"](cap_file) except (OSError, ParseError) as error: error_msg = _( - "%s web service was not found in fetched capabilities file from <%s>:\n%s\n" - % (self.ws, self.conn["url"], str(error)) + "%s web service was not found in fetched capabilities file from " + "<%s>:\n%s\n" % (self.ws, self.conn["url"], str(error)) ) if Debug.GetLevel() != 0: Debug.msg(1, error_msg) @@ -980,7 +980,8 @@ def addlayer(layer, item): item, { "type": "layer", # is it layer or style? - "layer": layer, # Layer instance from web_services.cap_interface + # Layer instance from web_services.cap_interface + "layer": layer, "style": def_st, }, ) # layer can have assigned default style diff --git a/gui/wxpython/wxplot/dialogs.py b/gui/wxpython/wxplot/dialogs.py index 7fbf0b9f9bb..ac23bb61547 100755 --- a/gui/wxpython/wxplot/dialogs.py +++ b/gui/wxpython/wxplot/dialogs.py @@ -814,7 +814,8 @@ def _do_layout(self): btnSave.Bind(wx.EVT_BUTTON, self.OnSave) btnSave.SetToolTip( _( - "Apply and save changes to user settings file (default for next sessions)" + "Apply and save changes to user settings file (default for next " + "sessions)" ) ) btnCancel.SetToolTip(_("Close dialog and ignore changes")) @@ -1209,7 +1210,8 @@ def _do_layout(self): type.SetStringSelection(prop["type"]) type.SetToolTip( _( - "Automatic axis scaling, custom max and min, or scale matches data range (min)" + "Automatic axis scaling, custom max and min, or scale matches data " + "range (min)" ) ) self.wxId[atype]["type"] = type.GetId() @@ -1323,7 +1325,8 @@ def _do_layout(self): btnOk.SetToolTip(_("Apply changes for the current session and close dialog")) btnSave.SetToolTip( _( - "Apply and save changes to user settings file (default for next sessions)" + "Apply and save changes to user settings file (default for next " + "sessions)" ) ) btnCancel.SetToolTip(_("Close dialog and ignore changes")) @@ -1470,8 +1473,8 @@ def UpdateSettings(self): self.wxId["grid"]["enabled"] ).IsChecked() - # this makes more sense in the text properties, including for settings update. But will need to change - # layout for controls to text dialog too. + # this makes more sense in the text properties, including for settings update. + # But will need to change layout for controls to text dialog too. self.properties["font"]["prop"]["legendSize"] = self.FindWindowById( self.wxId["font"]["legendSize"] ).GetValue() diff --git a/gui/wxpython/wxplot/profile.py b/gui/wxpython/wxplot/profile.py index 591608767d7..1b55da68919 100644 --- a/gui/wxpython/wxplot/profile.py +++ b/gui/wxpython/wxplot/profile.py @@ -234,9 +234,11 @@ def SetupProfile(self): # transect self.seglist.append( ( - segment_geodesic_cum_dist - if self._is_lat_lon_proj and haveCtypes - else cumdist, + ( + segment_geodesic_cum_dist + if self._is_lat_lon_proj and haveCtypes + else cumdist + ), val, ) ) diff --git a/gui/wxpython/wxplot/scatter.py b/gui/wxpython/wxplot/scatter.py index 0b53a1fe138..6022f7add4b 100644 --- a/gui/wxpython/wxplot/scatter.py +++ b/gui/wxpython/wxplot/scatter.py @@ -29,7 +29,8 @@ class ScatterFrame(BasePlotFrame): - """Mainframe for displaying bivariate scatter plot of two raster maps. Uses wx.lib.plot.""" + """Mainframe for displaying bivariate scatter plot of two raster maps. Uses + wx.lib.plot.""" def __init__( self, diff --git a/imagery/CMakeLists.txt b/imagery/CMakeLists.txt new file mode 100644 index 00000000000..6c5a1868844 --- /dev/null +++ b/imagery/CMakeLists.txt @@ -0,0 +1,138 @@ +build_program_in_subdir(i.albedo DEPENDS grass_imagery grass_raster + grass_vector grass_gis) +build_program_in_subdir(i.aster.toar DEPENDS grass_imagery grass_raster + grass_vector grass_gis) + +build_program_in_subdir( + i.atcorr + DEPENDS + grass_imagery + grass_raster + grass_vector + grass_gis + SRC_REGEX + "*.cpp") + +build_program_in_subdir(i.biomass DEPENDS grass_imagery grass_raster + grass_vector grass_gis) +build_program_in_subdir(i.cca DEPENDS grass_imagery grass_raster grass_vector + grass_gis) +build_program_in_subdir( + i.cluster + DEPENDS + grass_imagery + grass_raster + grass_vector + grass_gis + grass_cluster) + +build_program_in_subdir(i.eb.evapfr DEPENDS grass_imagery grass_raster + grass_vector grass_gis) +build_program_in_subdir(i.eb.eta DEPENDS grass_imagery grass_raster + grass_vector grass_gis) +build_program_in_subdir(i.eb.hsebal01 DEPENDS grass_imagery grass_raster + grass_vector grass_gis) +build_program_in_subdir(i.eb.netrad DEPENDS grass_imagery grass_raster + grass_vector grass_gis) +build_program_in_subdir(i.eb.soilheatflux DEPENDS grass_imagery grass_raster + grass_vector grass_gis) + +build_program_in_subdir(i.evapo.mh DEPENDS grass_imagery grass_raster + grass_vector grass_gis) +build_program_in_subdir(i.evapo.pm DEPENDS grass_imagery grass_raster + grass_vector grass_gis) +build_program_in_subdir(i.evapo.pt DEPENDS grass_imagery grass_raster + grass_vector grass_gis) +build_program_in_subdir(i.evapo.time DEPENDS grass_imagery grass_raster + grass_vector grass_gis) +build_program_in_subdir(i.emissivity DEPENDS grass_imagery grass_raster + grass_vector grass_gis) +build_program_in_subdir( + i.find + DEPENDS + grass_imagery + grass_raster + grass_vector + grass_gis + PACKAGE + "grassmods" + RUNTIME_OUTPUT_DIR + etc) + +build_program_in_subdir(i.gensig DEPENDS grass_imagery grass_raster + grass_vector grass_gis) + +build_program_in_subdir(i.gensigset DEPENDS grass_imagery grass_raster + grass_vector grass_gis) + +build_program_in_subdir(i.group DEPENDS grass_imagery grass_raster grass_vector + grass_gis) + +build_program_in_subdir(i.his.rgb DEPENDS grass_imagery grass_raster + grass_vector grass_gis) + +build_program_in_subdir(i.landsat.toar DEPENDS grass_imagery grass_raster + grass_vector grass_gis) + +build_program_in_subdir(i.maxlik DEPENDS grass_imagery grass_raster + grass_vector grass_gis) + +build_program_in_subdir(i.modis.qc DEPENDS grass_imagery grass_raster + grass_vector grass_gis) + +build_program_in_subdir(i.rectify DEPENDS grass_imagery grass_raster + grass_vector grass_gis) + +build_program_in_subdir(i.rgb.his DEPENDS grass_imagery grass_raster + grass_vector grass_gis) + +build_program_in_subdir( + i.segment + DEPENDS + grass_imagery + grass_raster + grass_vector + grass_gis + grass_segment) + +build_program_in_subdir(i.smap DEPENDS grass_imagery grass_raster grass_vector + grass_gis) + +build_program_in_subdir(i.target DEPENDS grass_imagery grass_raster + grass_vector grass_gis) + +build_program_in_subdir(i.topo.corr DEPENDS grass_imagery grass_raster + grass_vector grass_gis) + +build_program_in_subdir(i.pca DEPENDS grass_imagery grass_raster grass_vector + grass_gis) + +build_program_in_subdir(i.vi DEPENDS grass_imagery grass_raster grass_vector + grass_gis) + +build_program_in_subdir(i.zc DEPENDS grass_imagery grass_raster grass_vector + grass_gis) + +build_program_in_subdir( + i.fft + DEPENDS + grass_imagery + grass_raster + grass_gmath + grass_gis + PRIMARY_DEPENDS + FFTW) + +build_program_in_subdir( + i.ifft + DEPENDS + grass_gis + grass_raster + grass_gmath + grass_btree2 + PRIMARY_DEPENDS + FFTW) + +build_program_in_subdir(i.landsat.acca DEPENDS grass_raster grass_gis) + +add_subdirectory(i.ortho.photo) diff --git a/imagery/i.atcorr/create_iwave.py b/imagery/i.atcorr/create_iwave.py index eb79602dd0d..863b4416a84 100644 --- a/imagery/i.atcorr/create_iwave.py +++ b/imagery/i.atcorr/create_iwave.py @@ -20,8 +20,10 @@ Updated by: Anne Ghisla, 2010 Bug fix (9/12/2010) by Daniel: - 1) function interpolate_band was not generating the spectral response for the last value in the filter function. Fixed - 2) function pretty_print was not printing the 8th value of every line, cutting the filter function short. + 1) function interpolate_band was not generating the spectral response for the last + value in the filter function. Fixed + 2) function pretty_print was not printing the 8th value of every line, cutting the + filter function short. """ import os @@ -141,9 +143,10 @@ def interpolate_band(values, step=2.5): # how many spectral responses? expected = np.ceil((stop - start) / step) - assert ( - len(filter_f) == expected - ), "Number of interpolated spectral responses not equal to expected number of interpolations" + assert len(filter_f) == expected, ( + "Number of interpolated spectral responses not equal to expected number of " + "interpolations" + ) # convert limits from nanometers to micrometers lowerlimit = start / 1000 diff --git a/imagery/i.ortho.photo/CMakeLists.txt b/imagery/i.ortho.photo/CMakeLists.txt new file mode 100644 index 00000000000..ec829a3b73b --- /dev/null +++ b/imagery/i.ortho.photo/CMakeLists.txt @@ -0,0 +1,22 @@ +build_library_in_subdir( + lib + NAME + grass_iortho + DEPENDS + grass_gis + grass_imagery + grass_gmath) + +build_program_in_subdir(i.ortho.camera DEPENDS grass_iortho) + +build_program_in_subdir(i.ortho.elev DEPENDS grass_iortho) + +build_program_in_subdir(i.ortho.init DEPENDS grass_iortho) + +build_program_in_subdir(i.ortho.photo DEPENDS grass_iortho) + +build_program_in_subdir(i.ortho.rectify DEPENDS grass_iortho) + +build_program_in_subdir(i.ortho.target DEPENDS grass_iortho) + +build_program_in_subdir(i.ortho.transform DEPENDS grass_iortho) diff --git a/imagery/i.pca/testsuite/test_pca.py b/imagery/i.pca/testsuite/test_pca.py index 9da7991f876..8e9df84f2eb 100644 --- a/imagery/i.pca/testsuite/test_pca.py +++ b/imagery/i.pca/testsuite/test_pca.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + from grass.gunittest.case import TestCase diff --git a/imagery/i.segment/testsuite/test_isegment.py b/imagery/i.segment/testsuite/test_isegment.py index 09046f980af..66d24d41661 100644 --- a/imagery/i.segment/testsuite/test_isegment.py +++ b/imagery/i.segment/testsuite/test_isegment.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + from grass.gunittest.case import TestCase diff --git a/imagery/i.signatures/testsuite/test_i_signatures.py b/imagery/i.signatures/testsuite/test_i_signatures.py index 34f38774bc0..651d510ed03 100644 --- a/imagery/i.signatures/testsuite/test_i_signatures.py +++ b/imagery/i.signatures/testsuite/test_i_signatures.py @@ -8,6 +8,7 @@ Read the file COPYING that comes with GRASS for details """ + import os import shutil import json diff --git a/imagery/i.svm.predict/testsuite/test_i_svm_predict.py b/imagery/i.svm.predict/testsuite/test_i_svm_predict.py index 706af4f4fa2..3662124f45d 100644 --- a/imagery/i.svm.predict/testsuite/test_i_svm_predict.py +++ b/imagery/i.svm.predict/testsuite/test_i_svm_predict.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + import unittest import shutil diff --git a/imagery/i.svm.train/testsuite/test_i_svm_train.py b/imagery/i.svm.train/testsuite/test_i_svm_train.py index d895ffcd22f..f097405d98f 100644 --- a/imagery/i.svm.train/testsuite/test_i_svm_train.py +++ b/imagery/i.svm.train/testsuite/test_i_svm_train.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + import os import unittest import ctypes diff --git a/imagery/i.vi/testsuite/test_vi.py b/imagery/i.vi/testsuite/test_vi.py index a0da8245a5e..0c383417257 100644 --- a/imagery/i.vi/testsuite/test_vi.py +++ b/imagery/i.vi/testsuite/test_vi.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + from grass.gunittest.case import TestCase diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt new file mode 100644 index 00000000000..e17cdf9ae5f --- /dev/null +++ b/include/CMakeLists.txt @@ -0,0 +1,39 @@ +file(GLOB_RECURSE SRCHS "*.h") +set(include_depends) +foreach(srch ${SRCHS}) + get_filename_component(srch_DIR ${srch} DIRECTORY) + get_filename_component(srch_NAME ${srch} NAME) + string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" dsth_DIR "${srch_DIR}") + set(output_dir ${GISBASE}/include/${dsth_DIR}) + add_custom_command( + OUTPUT ${output_dir}/${srch_NAME} + COMMAND ${CMAKE_COMMAND} -E make_directory ${output_dir} + COMMAND ${CMAKE_COMMAND} -E copy ${srch} ${output_dir} + COMMENT "Copy ${srch} to ${output_dir}/${srch_NAME}") + list(APPEND include_depends ${output_dir}/${srch_NAME}) +endforeach() + +add_custom_target(copy_header DEPENDS ${include_depends} LIB_PYTHON) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/grass/version.h.in + "${GISBASE}/include/grass/version.h") + +message(STATUS "Creating ${GISBASE}/include/grass/config.h") + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake.in + "${GISBASE}/include/grass/config.h") + +file(WRITE ${GISBASE}/include/grass/copying.h "") +file(STRINGS ${CMAKE_SOURCE_DIR}/COPYING copying_lines) +foreach(copying_line ${copying_lines}) + file(APPEND ${GISBASE}/include/grass/copying.h "\"${copying_line} \\n\"\n") +endforeach() + +file(WRITE ${GISBASE}/include/grass/citing.h "") +file(STRINGS ${CMAKE_SOURCE_DIR}/CITING citing_lines) +foreach(citing_line ${citing_lines}) + file(APPEND ${GISBASE}/include/grass/citing.h "\"${citing_line}\\n\"\n") +endforeach() + +# TODO file(READ ${CMAKE_SOURCE_DIR}/config.status config_status_header) +file(WRITE ${GISBASE}/include/grass/confparms.h "\"/* */\\n\"") diff --git a/include/config.h.cmake.in b/include/config.h.cmake.in new file mode 100644 index 00000000000..cd2dcf6379d --- /dev/null +++ b/include/config.h.cmake.in @@ -0,0 +1,330 @@ +/* + #Generated by cmake from include/config.h.cmake.in + * config.h.cmake.in + */ + +#ifndef _config_h +#define _config_h + +#cmakedefine GDEBUG ${GDEBUG} + +/* define _OE_SOCKETS flag (OS/390 sys/socket.h) */ +#cmakedefine _OE_SOCKETS ${_OE_SOCKETS} + +/* define _REENTRANT flag (for SunOS) */ +#cmakedefine _REENTRANT ${_REENTRANT} + +/* define USE_DELTA_FOR_TZ (for AIX) */ +#cmakedefine USE_DELTA_FOR_TZ ${USE_DELTA_FOR_TZ} + +/* define for Windows static build */ +#cmakedefine STATIC_BUILD ${STATIC_BUILD} + +/* define if limits.h exists */ +#cmakedefine HAVE_LIMITS_H ${HAVE_LIMITS_H} + +/* define if termio.h exists */ +#cmakedefine HAVE_TERMIO_H ${HAVE_TERMIO_H} + +/* define if termios.h exists */ +#cmakedefine HAVE_TERMIOS_H ${HAVE_TERMIOS_H} + +/* define if unistd.h exists */ +#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H} + +/* define if values.h exists */ +#cmakedefine HAVE_VALUES_H ${HAVE_VALUES_H} + +/* define if zlib.h exists */ +#cmakedefine HAVE_ZLIB_H ${HAVE_ZLIB_H} + +/* define if bzlib.h exists */ +#cmakedefine HAVE_BZLIB_H ${HAVE_BZLIB_H} + +/* define if zstd.h exists */ +#cmakedefine HAVE_ZSTD_H ${HAVE_ZSTD_H} + +/* define if sys/ioctl.h exists */ +#cmakedefine HAVE_SYS_IOCTL_H ${HAVE_SYS_IOCTL_H} + +/* define if sys/mtio.h exists */ +#cmakedefine HAVE_SYS_MTIO_H ${HAVE_SYS_MTIO_H} + +/* define if sys/resource.h exists */ +#cmakedefine HAVE_SYS_RESOURCE_H ${HAVE_SYS_RESOURCE_H} + +/* define if sys/time.h exists */ +#cmakedefine HAVE_SYS_TIME_H ${HAVE_SYS_TIME_H} + +/* define if time.h and sys/time.h can be included together */ +#cmakedefine TIME_WITH_SYS_TIME ${TIME_WITH_SYS_TIME} + +/* define if sys/timeb.h exists */ +#cmakedefine HAVE_SYS_TIMEB_H ${HAVE_SYS_TIMEB_H} + +/* define if sys/types.h exists */ +#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H} + +/* define if sys/utsname.h exists */ +#cmakedefine HAVE_SYS_UTSNAME_H ${HAVE_SYS_UTSNAME_H} + +/* define if g2c.h exists */ +#cmakedefine HAVE_G2C_H ${HAVE_G2C_H} + +/* define if f2c.h exists */ +#cmakedefine HAVE_F2C_H ${HAVE_F2C_H} + +/* define if cblas.h exists */ +#cmakedefine HAVE_CBLAS_H ${HAVE_CBLAS_H} + +/* define if clapack.h exists */ +#cmakedefine HAVE_CLAPACK_H ${HAVE_CLAPACK_H} + +/* define if "long long" is available */ +#cmakedefine HAVE_LONG_LONG_INT ${HAVE_LONG_LONG_INT} + +/* Define the return type of signal handlers */ +#define RETSIGTYPE ${RETSIGTYPE} + +/* define if ftime() exists */ +#cmakedefine HAVE_FTIME ${HAVE_FTIME} + +/* define if gethostname() exists */ +#cmakedefine HAVE_GETHOSTNAME ${HAVE_GETHOSTNAME} + +/* define if gettimeofday() exists */ +#cmakedefine HAVE_GETTIMEOFDAY ${HAVE_GETTIMEOFDAY} + +/* define if lseek() exists */ +#cmakedefine HAVE_LSEEK ${HAVE_LSEEK} + +/* define if time() exists */ +#cmakedefine HAVE_TIME ${HAVE_TIME} + +/* define if uname() exists */ +#cmakedefine HAVE_UNAME ${HAVE_UNAME} + +/* define if seteuid() exists */ +#cmakedefine HAVE_SETEUID ${HAVE_SETEUID} + +/* define if setpriority() exists */ +#cmakedefine HAVE_SETPRIORITY ${HAVE_SETPRIORITY} + +/* define if setreuid() exists */ +#cmakedefine HAVE_SETREUID ${HAVE_SETREUID} + +/* define if setruid() exists */ +#cmakedefine SETPGRP_VOID ${SETPGRP_VOID} + +/* define if setpgrp() takes no argument */ +#cmakedefine SETPGRP_VOID ${SETPGRP_VOID} + +/* define if drand48() exists */ +#cmakedefine HAVE_DRAND48 ${HAVE_DRAND48} + +/* define if nanosleep() exists */ +#cmakedefine HAVE_NANOSLEEP ${HAVE_NANOSLEEP} + +/* define if asprintf() exists */ +#cmakedefine HAVE_ASPRINTF ${HAVE_ASPRINTF} + +/* define if SQLite is to be used */ +#cmakedefine HAVE_SQLITE ${HAVE_SQLITE} + +/* define if postgres is to be used */ +#cmakedefine HAVE_POSTGRES ${HAVE_POSTGRES} + +/* define if MySQL is to be used */ +#cmakedefine HAVE_MYSQL_H ${HAVE_MYSQL_H} + +/* define if GDAL is to be used */ +#cmakedefine HAVE_GDAL ${HAVE_GDAL} + +/* define if OGR is to be used */ +#cmakedefine HAVE_OGR ${HAVE_OGR} + +/* define if GEOS is to be used */ +#cmakedefine HAVE_GEOS ${HAVE_GEOS} + +/* define if postgres client header exists */ +#cmakedefine HAVE_LIBPQ_FE_H ${HAVE_LIBPQ_FE_H} + +/* define if PQcmdTuples in lpq */ +#cmakedefine HAVE_PQCMDTUPLES ${HAVE_PQCMDTUPLES} + +/* define if ODBC exists */ +#cmakedefine HAVE_SQL_H ${HAVE_SQL_H} + +/* define if tiffio.h exists */ +#cmakedefine HAVE_TIFFIO_H ${HAVE_TIFFIO_H} + +/* define if NetCDF exists */ +#cmakedefine HAVE_NETCDF ${HAVE_NETCDF} + +/* define if png.h exists */ +#cmakedefine HAVE_PNG_H ${HAVE_PNG_H} + +/* define if jpeglib.h exists */ +#cmakedefine HAVE_JPEGLIB_H ${HAVE_JPEGLIB_H} + +/* define if proj.h exists */ +#cmakedefine PROJMAJOR ${PROJMAJOR} +#cmakedefine HAVE_PROJ_H ${HAVE_PROJ_H} + +/* define if fftw3.h exists */ +#cmakedefine HAVE_FFTW3_H ${HAVE_FFTW3_H} + +/* define if fftw.h exists */ +#cmakedefine HAVE_FFTW_H ${HAVE_FFTW_H} + +/* define if dfftw.h exists */ +#cmakedefine HAVE_DFFTW_H ${HAVE_DFFTW_H} + +/* define if BLAS exists */ +#cmakedefine HAVE_LIBBLAS ${HAVE_LIBBLAS} + +/* define if LAPACK exists */ +#cmakedefine HAVE_LIBLAPACK ${HAVE_LIBLAPACK} + +/* define if ATLAS exists */ +#cmakedefine HAVE_LIBATLAS ${HAVE_LIBATLAS} + +/* define if dbm.h exists */ +#cmakedefine HAVE_DBM_H ${HAVE_DBM_H} + +/* define if readline exists */ +#cmakedefine HAVE_READLINE_READLINE_H ${HAVE_READLINE_READLINE_H} + +/* define if history exists */ +#cmakedefine HAVE_READLINE_HISTORY_H ${HAVE_READLINE_HISTORY_H} + +/* define if ft2build.h exists */ +#cmakedefine HAVE_FT2BUILD_H ${HAVE_FT2BUILD_H} + +/* Whether or not we are using G_socks for display communications */ +#cmakedefine USE_G_SOCKS ${USE_G_SOCKS} + +/* define if X is disabled or unavailable */ +#cmakedefine X_DISPLAY_MISSING ${X_DISPLAY_MISSING} + +/* define if libintl.h exists */ +#cmakedefine HAVE_LIBINTL_H ${HAVE_LIBINTL_H} + +/* define if iconv.h exists */ +#cmakedefine HAVE_ICONV_H ${HAVE_ICONV_H} + +/* define if NLS requested */ +#cmakedefine USE_NLS ${USE_NLS} + +/* define if putenv() exists */ +#cmakedefine HAVE_PUTENV ${HAVE_PUTENV} + +/* define if setenv() exists */ +#cmakedefine HAVE_SETENV ${HAVE_SETENV} + +/* define if socket() exists */ +#cmakedefine HAVE_SOCKET ${HAVE_SOCKET} + +/* define if glXCreatePbuffer exists */ +#cmakedefine HAVE_PBUFFERS ${HAVE_PBUFFERS} + +/* define if glXCreateGLXPixmap exists */ +#cmakedefine HAVE_PIXMAPS ${HAVE_PIXMAPS} + +/* define if OpenGL uses X11 */ +#cmakedefine OPENGL_X11 ${OPENGL_X11} + +/* define if OpenGL uses Aqua (MacOS X) */ +#cmakedefine OPENGL_AQUA ${OPENGL_AQUA} +#define OPENGL_AGL 1 + +/* define if OpenGL uses Windows */ +#cmakedefine OPENGL_WINDOWS ${OPENGL_WINDOWS} + +/* define if regex.h exists */ +#cmakedefine HAVE_REGEX_H ${HAVE_REGEX_H} + +/* define if pcre.h exists */ +#cmakedefine HAVE_PCRE_H ${HAVE_PCRE_H} + +/* define if pthread.h exists */ +#cmakedefine HAVE_PTHREAD_H ${HAVE_PTHREAD_H} + +/* define if fseeko() exists */ +#cmakedefine HAVE_FSEEKO ${HAVE_FSEEKO} + +/* + * configuration information solely dependent on the above + * nothing below this point should need changing + */ + +#if defined(HAVE_VALUES_H) && !defined(HAVE_LIMITS_H) +#define INT_MIN -MAXINT +#endif + +/* + * Defines needed to get large file support - from cdrtools-2.01 + */ + +#define HAVE_LARGEFILES ${HAVE_LARGEFILES} + +/* define if langinfo.h exists */ +#cmakedefine HAVE_LANGINFO_H ${HAVE_LANGINFO_H} + +#if defined(__MINGW32__) && (!defined(_FILE_OFFSET_BITS) || (_FILE_OFFSET_BITS != 64)) +/* add/remove as needed */ +/* redefine off_t */ +#include +#define off_t off64_t +/* fseeko and ftello are safe because not defined by MINGW */ +#define HAVE_FSEEKO +#define fseeko fseeko64 +#define ftello ftello64 +/* redefine lseek */ +#include +#define lseek lseek64 +/* redefine stat and fstat */ +/* use _stati64 compatible with MSVCRT < 6.1 */ +#include +#define stat _stati64 +#define fstat _fstati64 + +#endif /* MINGW32 LFS */ + +#ifdef _MSC_VER +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#define fdopen _fdopen +#define open _open +#define read _read +#define write _write +#define close _close +#define unlink _unlink +#define getpid _getpid +#define creat _creat + +/* define gid_t type */ +typedef @GID_TYPE@ gid_t; + +/* define uid_t type */ +typedef @UID_TYPE@ uid_t; + +/* define pid_t type */ +typedef @PID_TYPE@ pid_t; + +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif + +#include +typedef SSIZE_T ssize_t; + +/* open for reading, writing, or both (not in fcntl.h) */ +#define O_ACCMODE (_O_RDONLY | _O_WRONLY | _O_RDWR) + +#endif //_MSC_VER + +/* To include export.h generated by cmake */ + +#define GRASS_CMAKE_BUILD 1 +#endif /* _config_h */ diff --git a/include/grass/calc.h b/include/grass/calc.h index 9b22a847160..ab89ef3155c 100644 --- a/include/grass/calc.h +++ b/include/grass/calc.h @@ -31,12 +31,18 @@ typedef struct func_desc { #define SET_NULL_F(x) (Rast_set_f_null_value((x), 1)) #define SET_NULL_D(x) (Rast_set_d_null_value((x), 1)) -extern volatile int floating_point_exception; -extern volatile int floating_point_exception_occurred; +#ifdef GRASS_CMAKE_BUILD +#include +#else +#define GRASS_CALC_EXPORT +#endif + +extern GRASS_CALC_EXPORT volatile int floating_point_exception; +extern GRASS_CALC_EXPORT volatile int floating_point_exception_occurred; extern int columns; -extern func_desc calc_func_descs[]; +extern GRASS_CALC_EXPORT func_desc calc_func_descs[]; #include diff --git a/include/grass/defs/gis.h b/include/grass/defs/gis.h index 4339fad72d1..c14d6fa1708 100644 --- a/include/grass/defs/gis.h +++ b/include/grass/defs/gis.h @@ -72,6 +72,27 @@ #define RELDIR "?" #endif +/* GDAL < 2.3 does not define HAVE_LONG_LONG when compiled with + * Visual Studio as for OSGeo4W, even though long long is available, + * and GIntBig falls back to long which is on Windows always 4 bytes. + * This patch ensures that GIntBig is defined as long long (8 bytes) + * if GDAL is compiled with Visual Studio and GRASS is compiled with + * MinGW. This patch must be applied before other GDAL/OGR headers are + * included, as done by gprojects.h and vector.h */ +#ifndef _MSC_VER +#if defined(__MINGW32__) && HAVE_GDAL +#include +#if GDAL_VERSION_NUM < 2030000 +#include +/* HAVE_LONG_LONG_INT comes from GRASS + * HAVE_LONG_LONG comes from GDAL */ +#if HAVE_LONG_LONG_INT && !defined(HAVE_LONG_LONG) +#define HAVE_LONG_LONG 1 +#endif +#endif +#endif +#endif /* _MSC_VER */ + /* adj_cellhd.c */ void G_adjust_Cell_head(struct Cell_head *, int, int); void G_adjust_Cell_head3(struct Cell_head *, int, int, int); @@ -479,7 +500,7 @@ void G_ls(const char *, FILE *); void G_ls_format(char **, int, int, FILE *); /* ls_filter.c */ -#ifdef HAVE_REGEX_H +#if defined(HAVE_REGEX_H) || defined(HAVE_PCRE_H) void *G_ls_regex_filter(const char *, int, int, int); void *G_ls_glob_filter(const char *, int, int); void G_free_ls_filter(void *); diff --git a/include/grass/iostream/mm.h b/include/grass/iostream/mm.h index 38b1feb9377..5b5cfa1e2d9 100644 --- a/include/grass/iostream/mm.h +++ b/include/grass/iostream/mm.h @@ -79,9 +79,15 @@ enum MM_stream_usage { MM_STREAM_USAGE_MAXIMUM }; +#ifdef GRASS_CMAKE_BUILD +#include +#else +#define GRASS_IOSTREAM_EXPORT +#endif + // Declarations of a very simple memory manager designed to work with // BTEs that rely on the underlying OS to manage physical memory. -class MM_register { +class GRASS_IOSTREAM_EXPORT MM_register { private: // The number of instances of this class and descendents that exist. static int instances; @@ -155,6 +161,6 @@ class mm_register_init { static mm_register_init source_file_mm_register_init; // Here is the single memory management object (defined in mm.C). -extern MM_register MM_manager; +extern GRASS_IOSTREAM_EXPORT MM_register MM_manager; #endif // _MM_H diff --git a/include/grass/iostream/rtimer.h b/include/grass/iostream/rtimer.h index d4107c92543..9a47308f1ec 100644 --- a/include/grass/iostream/rtimer.h +++ b/include/grass/iostream/rtimer.h @@ -36,13 +36,14 @@ #ifndef RTIMER_H #define RTIMER_H -#ifdef __MINGW32__ +#ifdef _WIN32 #include #include #include +#ifdef __MINGW32__ #include - +#endif typedef struct { time_t tv1, tv2; } Rtimer; diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 00000000000..6248150480e --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,235 @@ +set(use_math_DEFS "") +if(MSVC) + set(use_math_DEFS "-D_USE_MATH_DEFINES=1") +endif() + +build_library_in_subdir(datetime) + +add_subdirectory(gis) + +build_library_in_subdir( + driver + DEFS + "${use_math_DEFS}" + DEPENDS + grass_gis + FREETYPE + ICONV + ZLIB) + +add_subdirectory(proj) + +file(GLOB raster_SRCS "./raster/*.c") +# list(APPEND raster_SRCS "./gis/gisinit.c") +build_library_in_subdir( + raster + DEFS + "-DGDAL_DYNAMIC=1;-DGDAL_LINK=1" + SOURCES + ${raster_SRCS} + DEPENDS + GDAL + PROJ + grass_gproj) + +if(TARGET LAPACK) + target_link_libraries(grass_raster LAPACK) +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + find_library(DL_LIBRARY dl) + mark_as_advanced(DL_LIBRARY) + target_link_libraries(grass_raster ${DL_LIBRARY}) +endif() + +configure_file(external/ccmath/ccmath.h ${GISBASE}/include/grass/ccmath_grass.h + COPYONLY) +build_library_in_subdir(external/ccmath) + +build_library_in_subdir(external/shapelib NAME grass_shape HEADERS "shapefil.h") + +build_library_in_subdir(external/parson NAME grass_parson HEADERS "parson.h") + +build_library_in_subdir( + gmath + DEPENDS + grass_ccmath + grass_gis + DEFS + "${use_math_DEFS}" + OPTIONAL_DEPENDS + FFTW + LAPACK + BLAS + OPENMP) + +build_library_in_subdir(linkm) + +file(GLOB pngdriver_SRCS "./pngdriver/*.c") +# list(APPEND pngdriver_SRCS "./driver/init.c") +if(NOT WITH_LIBPNG) + list(FILTER pngdriver_SRCS EXCLUDE REGEX "./pngdriver/.*_png.c") +endif() +build_library_in_subdir( + pngdriver + SOURCES + ${pngdriver_SRCS} + DEPENDS + grass_driver + grass_gis + ZLIB + OPTIONAL_DEPENDS + LIBPNG) +# INCLUDES "./driver") + +file(GLOB psdriver_SRCS "./psdriver/*.c") +list(APPEND psdriver_SRCS "./driver/init.c") +build_library_in_subdir( + psdriver + SOURCES + ${psdriver_SRCS} + DEPENDS + grass_driver + INCLUDES + "./driver") + +file(GLOB htmldriver_SRCS "./htmldriver/*.c") +list(APPEND htmldriver_SRCS "./driver/init.c") +build_library_in_subdir( + htmldriver + SOURCES + ${htmldriver_SRCS} + DEPENDS + grass_driver + INCLUDES + "./driver") + +set(_grass_display_DEFS) + +set(_grass_display_DEPENDS grass_driver grass_raster grass_htmldriver + grass_pngdriver grass_psdriver) + +if(WITH_CAIRO) + + set(_cairodriver_DEPENDS CAIRO FREETYPE grass_driver) + if(WITH_X11) + list(APPEND _cairodriver_DEPENDS X11) + endif() + + file(GLOB cairodriver_SRCS "./cairodriver/*.c") + list(APPEND cairodriver_SRCS "./driver/init.c") + build_library_in_subdir(cairodriver DEPENDS ${_cairodriver_DEPENDS} SOURCES + ${cairodriver_SRCS}) + + set(_grass_display_DEFS "-DUSE_CAIRO") + list(APPEND _grass_display_DEPENDS grass_cairodriver) +endif() + +build_library_in_subdir(bitmap SOURCES "./bitmap/bitmap.c" "./bitmap/sparse.c" + DEPENDS grass_linkm) + +build_library_in_subdir(btree) + +build_library_in_subdir(btree2 HEADERS "kdtree.h" DEPENDS grass_gis) + +build_library_in_subdir(display DEFS ${_grass_display_DEFS} DEPENDS + ${_grass_display_DEPENDS}) + +add_subdirectory(db) + +add_subdirectory(fonts) + +add_subdirectory(vector) + +build_library_in_subdir(imagery DEPENDS grass_vector) + +build_library_in_subdir(cluster DEPENDS grass_imagery) + +build_library_in_subdir(rowio DEPENDS grass_gis) + +build_library_in_subdir(segment DEPENDS grass_gis) # addeed DEPENDS grass_gis + # for uninstd.h + +add_subdirectory(rst) + +build_library_in_subdir( + lidar + DEPENDS + grass_vector + grass_raster + grass_dbmibase + grass_segment + HEADERS + "lidar.h") + +build_library_in_subdir(raster3d DEPENDS grass_raster) + +build_program_in_subdir( + raster3d/test + NAME + test.raster3d.lib + DEPENDS + grass_gis + grass_raster3d + grass_raster) + +build_library_in_subdir( + gpde + HEADERS + "N_*.h" + DEPENDS + grass_gis + grass_raster3d + grass_gmath + OPTIONAL_DEPENDS + OPENMP) + +build_library_in_subdir(dspf DEPENDS grass_gis) + +build_library_in_subdir(symbol NAME grass_sym DEPENDS grass_gis) +add_custom_command( + TARGET grass_sym + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/symbol/symbol ${GISBASE}/etc/symbol) + +add_subdirectory(init) + +build_library_in_subdir(cdhc DEPENDS grass_raster) + +build_library_in_subdir(stats DEPENDS grass_raster) + +build_library_in_subdir(arraystats DEPENDS grass_gis) + +if(WITH_OPENGL) + build_library_in_subdir( + ogsf + DEPENDS + grass_raster + grass_raster3d + grass_vector + grass_bitmap + OPENGL + TIFF) + + build_library_in_subdir( + nviz + DEPENDS + grass_display + grass_raster + grass_vector + grass_bitmap + grass_ogsf + OPENGL + TIFF) +endif() + +add_subdirectory(temporal) + +build_library_in_subdir(iostream SRC_REGEX "*.cpp" DEPENDS grass_gis) + +build_library_in_subdir(manage DEPENDS grass_raster grass_vector grass_raster3d) +file(COPY manage/element_list DESTINATION ${GISBASE}/etc) +install(FILES ${GISBASE}/etc/element_list DESTINATION etc) + +build_library_in_subdir(calc DEPENDS grass_raster) diff --git a/lib/cairodriver/graph.c b/lib/cairodriver/graph.c index 529cc65d347..db2fa62e45f 100644 --- a/lib/cairodriver/graph.c +++ b/lib/cairodriver/graph.c @@ -29,7 +29,7 @@ #endif #include -#ifndef __MINGW32__ +#ifndef _WIN32 #include #include #include @@ -389,7 +389,7 @@ static int ends_with(const char *string, const char *suffix) static void map_file(void) { -#ifndef __MINGW32__ +#ifndef _WIN32 size_t size = HEADER_SIZE + ca.width * ca.height * sizeof(unsigned int); void *ptr; int fd; diff --git a/lib/cairodriver/text.c b/lib/cairodriver/text.c index 49c8e80cd93..12f22172071 100644 --- a/lib/cairodriver/text.c +++ b/lib/cairodriver/text.c @@ -11,6 +11,9 @@ \author Lars Ahlzen (original contributor) \author Glynn Clements */ +#if defined(_MSC_VER) +#include +#endif #include #include "cairodriver.h" diff --git a/lib/calc/calc.c b/lib/calc/calc.c index 4894d4e14da..031a97150e5 100644 --- a/lib/calc/calc.c +++ b/lib/calc/calc.c @@ -20,7 +20,7 @@ static void handle_fpe(int n UNUSED) void pre_exec(void) { -#ifndef __MINGW32__ +#ifndef _WIN32 #ifdef SIGFPE struct sigaction act; @@ -37,7 +37,7 @@ void pre_exec(void) void post_exec(void) { -#ifndef __MINGW32__ +#ifndef _WIN32 #ifdef SIGFPE struct sigaction act; diff --git a/lib/db/CMakeLists.txt b/lib/db/CMakeLists.txt new file mode 100644 index 00000000000..5fc3119b06e --- /dev/null +++ b/lib/db/CMakeLists.txt @@ -0,0 +1,40 @@ +file(GLOB dbmibase_SRCS "./dbmi_base/*.c") +if(MSVC) + set(dbmibase_INCLUDES "./dbmi_base" "./dbmi_base/msvc") + list(APPEND dbmibase_SRCS "./dbmi_base/msvc/dirent.c") +endif() + +build_library_in_subdir( + dbmi_base + NAME + grass_dbmibase + INCLUDES + ${dbmibase_INCLUDES} + SOURCES + ${dbmibase_SRCS} + DEPENDS + grass_gis + HEADERS + "dbstubs.h") + +build_library_in_subdir( + dbmi_client + NAME + grass_dbmiclient + DEPENDS + grass_dbmibase + INCLUDES + "./dbmi_base") + +build_library_in_subdir(stubs NAME grass_dstubs DEPENDS grass_dbmibase) + +build_library_in_subdir( + dbmi_driver + NAME + grass_dbmidriver + DEPENDS + grass_dstubs + INCLUDES + "./dbmi_base") + +add_subdirectory(sqlp) diff --git a/lib/db/dbmi_base/dbmscap.c b/lib/db/dbmi_base/dbmscap.c index 25f1e0a1eec..c6ce8f755de 100644 --- a/lib/db/dbmi_base/dbmscap.c +++ b/lib/db/dbmi_base/dbmscap.c @@ -156,7 +156,7 @@ dbDbmscap *db_read_dbmscap(void) /* START OF NEW CODE FOR SEARCH IN $(GISBASE)/driver/db/ */ /* opend db drivers directory */ -#ifdef __MINGW32__ +#ifdef _WIN32 dirpath = G_malloc(strlen("\\driver\\db\\") + strlen(G_gisbase()) + 1); sprintf(dirpath, "%s\\driver\\db\\", G_gisbase()); G_convert_dirseps_to_host(dirpath); @@ -179,7 +179,7 @@ dbDbmscap *db_read_dbmscap(void) if ((strcmp(ent->d_name, ".") == 0) || (strcmp(ent->d_name, "..") == 0)) continue; -#ifdef __MINGW32__ +#ifdef _WIN32 /* skip manifest files on Windows */ if (strstr(ent->d_name, ".manifest")) continue; @@ -188,7 +188,7 @@ dbDbmscap *db_read_dbmscap(void) /* Remove '.exe' from name (windows extension) */ name = G_str_replace(ent->d_name, ".exe", ""); -#ifdef __MINGW32__ +#ifdef _WIN32 dirpath = G_malloc(strlen("\\driver\\db\\") + strlen(G_gisbase()) + strlen(ent->d_name) + 1); sprintf(dirpath, "%s\\driver\\db\\%s", G_gisbase(), ent->d_name); diff --git a/lib/db/dbmi_base/dirent.c b/lib/db/dbmi_base/dirent.c index 1823ba64726..708795bd4da 100644 --- a/lib/db/dbmi_base/dirent.c +++ b/lib/db/dbmi_base/dirent.c @@ -22,6 +22,7 @@ /* NOTE: these should come from or from */ #ifndef R_OK +#if !defined(HAVE_UNISTD_H) #define R_OK 4 #endif #ifndef W_OK @@ -30,6 +31,7 @@ #ifndef X_OK #define X_OK 1 #endif +#endif static int cmp_dirent(const void *, const void *); static int get_perm(char *); diff --git a/lib/db/dbmi_base/login.c b/lib/db/dbmi_base/login.c index d79fc84e6cf..755aa9e24d5 100644 --- a/lib/db/dbmi_base/login.c +++ b/lib/db/dbmi_base/login.c @@ -167,8 +167,9 @@ static int write_file(LOGIN *login) /* fchmod is not available on Windows */ /* fchmod ( fileno(fd), S_IRUSR | S_IWUSR ); */ +#ifndef _MSC_VER chmod(file, S_IRUSR | S_IWUSR); - +#endif for (i = 0; i < login->n; i++) { fprintf(fd, "%s|%s", login->data[i].driver, login->data[i].database); if (login->data[i].user) { diff --git a/lib/db/dbmi_base/msvc/dirent.c b/lib/db/dbmi_base/msvc/dirent.c new file mode 100644 index 00000000000..44f7a6a7d29 --- /dev/null +++ b/lib/db/dbmi_base/msvc/dirent.c @@ -0,0 +1,101 @@ + +#include +#include +#include + +typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */ + +struct DIR { + handle_type handle; /* -1 for failed rewind */ + struct _finddata_t info; + struct dirent result; /* d_name null iff first time */ + char *name; /* null-terminated char string */ +}; + +DIR *opendir(const char *name) +{ + DIR *dir = 0; + + if (name && name[0]) { + size_t base_length = strlen(name); + const char *all = /* search pattern must end with suitable wildcard */ + strchr("/\\", name[base_length - 1]) ? "*" : "/*"; + + if ((dir = (DIR *)malloc(sizeof *dir)) != 0 && + (dir->name = (char *)malloc(base_length + strlen(all) + 1)) != 0) { + strcat(strcpy(dir->name, name), all); + + if ((dir->handle = + (handle_type)_findfirst(dir->name, &dir->info)) != -1) { + dir->result.d_name = 0; + } + else /* rollback */ + { + free(dir->name); + free(dir); + dir = 0; + } + } + else /* rollback */ + { + free(dir); + dir = 0; + errno = ENOMEM; + } + } + else { + errno = EINVAL; + } + + return dir; +} + +int closedir(DIR *dir) +{ + int result = -1; + + if (dir) { + if (dir->handle != -1) { + result = _findclose(dir->handle); + } + + free(dir->name); + free(dir); + } + + if (result == -1) /* map all errors to EBADF */ + { + errno = EBADF; + } + + return result; +} + +struct dirent *readdir(DIR *dir) +{ + struct dirent *result = 0; + + if (dir && dir->handle != -1) { + if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) { + result = &dir->result; + result->d_name = dir->info.name; + } + } + else { + errno = EBADF; + } + + return result; +} + +void rewinddir(DIR *dir) +{ + if (dir && dir->handle != -1) { + _findclose(dir->handle); + dir->handle = (handle_type)_findfirst(dir->name, &dir->info); + dir->result.d_name = 0; + } + else { + errno = EBADF; + } +} diff --git a/lib/db/dbmi_base/msvc/dirent.h b/lib/db/dbmi_base/msvc/dirent.h new file mode 100644 index 00000000000..8cd2229e21f --- /dev/null +++ b/lib/db/dbmi_base/msvc/dirent.h @@ -0,0 +1,48 @@ +#ifndef DIRENT_INCLUDED +#define DIRENT_INCLUDED + +/* + + Declaration of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003. + Rights: See end of file. + +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DIR DIR; + +struct dirent { + char *d_name; +}; + +DIR *opendir(const char *); +int closedir(DIR *); +struct dirent *readdir(DIR *); +void rewinddir(DIR *); + +/* + + Copyright Kevlin Henney, 1997, 2003. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. + +*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/db/dbmi_client/start.c b/lib/db/dbmi_client/start.c index bc801685593..9017f31d4cc 100644 --- a/lib/db/dbmi_client/start.c +++ b/lib/db/dbmi_client/start.c @@ -16,7 +16,7 @@ #include #include -#ifdef __MINGW32__ +#ifdef _WIN32 #include #include #include @@ -30,7 +30,7 @@ static void close_on_exec(int fd) { -#ifndef __MINGW32__ +#ifndef _WIN32 int flags = fcntl(fd, F_GETFD); fcntl(fd, F_SETFD, flags | FD_CLOEXEC); @@ -136,7 +136,7 @@ dbDriver *db_start_driver(const char *name) /* run the driver as a child process and create pipes to its stdin, stdout */ -#ifdef __MINGW32__ +#ifdef _WIN32 #define pipe(fds) _pipe(fds, 250000, _O_BINARY | _O_NOINHERIT) #endif diff --git a/lib/db/sqlp/CMakeLists.txt b/lib/db/sqlp/CMakeLists.txt new file mode 100644 index 00000000000..eeead261d8a --- /dev/null +++ b/lib/db/sqlp/CMakeLists.txt @@ -0,0 +1,13 @@ +flex_target(sqlp.yy.c sqlp.l ${CMAKE_CURRENT_BINARY_DIR}/sqlp.yy.c) + +bison_target(sqlp.tab.c sqlp.y ${CMAKE_CURRENT_BINARY_DIR}/sqlp.tab.c) + +add_flex_bison_dependency(sqlp.yy.c sqlp.tab.c) + +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/sqlp.yy.c GENERATED) +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/sqlp.tab.c GENERATED) + +set(sqlp_SRCS alloc.c print.c sql.c ${CMAKE_CURRENT_BINARY_DIR}/sqlp.tab.c + ${CMAKE_CURRENT_BINARY_DIR}/sqlp.yy.c) + +build_module(NAME grass_sqlp SOURCES "${sqlp_SRCS}") diff --git a/lib/driver/font2.c b/lib/driver/font2.c index 7b80a5e8870..67e26572542 100644 --- a/lib/driver/font2.c +++ b/lib/driver/font2.c @@ -146,7 +146,7 @@ static void read_fontmap(const char *name) fp = fopen(buf, "r"); if (!fp) { G_warning("Unable to open font map '%s': %s. " - "Try running 'g.mkfontcap -o'", + "Try running 'g.mkfontcap --overwrite'", buf, strerror(errno)); return; } diff --git a/lib/dspf/viz.h b/lib/dspf/viz.h index 92abb658908..8fc8b6cf819 100644 --- a/lib/dspf/viz.h +++ b/lib/dspf/viz.h @@ -90,5 +90,9 @@ int print_head_info(file_info *); /* struct_copy.c */ int struct_copy(char *, char *, int); - -extern CELL_ENTRY cell_table[]; +#ifdef GRASS_CMAKE_BUILD +#include +#else +#define GRASS_DSPF_EXPORT +#endif +extern GRASS_DSPF_EXPORT CELL_ENTRY cell_table[]; diff --git a/lib/external/ccmath/ccmath.h b/lib/external/ccmath/ccmath.h index 5774271c2d9..d977c3791da 100644 --- a/lib/external/ccmath/ccmath.h +++ b/lib/external/ccmath/ccmath.h @@ -33,12 +33,19 @@ #endif /* Complex Types */ - #ifndef CPX +#ifndef _MSC_VER struct complex { double re, im; }; typedef struct complex Cpx; +#else +/* _MSVC has complex struct and cannot be used */ +struct gcomplex { + double re, im; +}; +typedef struct gcomplex Cpx; +#endif /* _MSC_VER */ #define CPX 1 #endif @@ -169,6 +176,8 @@ void unitary(Cpx *u, int n); void hmgen(Cpx *h, double *eval, Cpx *u, int n); +int csolv(Cpx *a, Cpx *b, int n); + /* utility routines for hermitian eigen problems */ void chouse(Cpx *a, double *d, double *ud, int n); diff --git a/lib/fonts/CMakeLists.txt b/lib/fonts/CMakeLists.txt new file mode 100644 index 00000000000..27a0ae8a7eb --- /dev/null +++ b/lib/fonts/CMakeLists.txt @@ -0,0 +1,5 @@ +add_custom_target( + fonts + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/fonts + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/fonts/[a-z]*.[a-z]* ${GISBASE}/fonts) diff --git a/lib/gis/CMakeLists.txt b/lib/gis/CMakeLists.txt new file mode 100644 index 00000000000..315c5b8a79f --- /dev/null +++ b/lib/gis/CMakeLists.txt @@ -0,0 +1,218 @@ +set(gislib_SRCS + adj_cellhd.c + aprintf.c + copy_dir.c + get_ellipse.c + ll_scan.c + open_misc.c + proj3.c + units.c + alloc.c + copy_file.c + get_projinfo.c + locale.c + overwrite.c + put_window.c + user_config.c + area.c + counter.c + get_window.c + location.c + pager.c + putenv.c + verbose.c + area_ellipse.c + date.c + getl.c + lrand48.c + parser.c + radii.c + view.c + area_poly1.c + datum.c + gisbase.c + ls.c + parser_dependencies.c + rd_cellhd.c + whoami.c + area_poly2.c + debug.c + gisdbase.c + ls_filter.c + parser_help.c + remove.c + win32_pipes.c + area_sphere.c + distance.c + gisinit.c + lz4.c + parser_html.c + rename.c + wind_2_box.c + ascii_chk.c + done_msg.c + handler.c + mach_name.c + parser_interface.c + rhumbline.c + wind_format.c + asprintf.c + endian.c + home.c + make_loc.c + parser_rest_md.c + rotate.c + wind_in.c + basename.c + env.c + ilist.c + make_mapset.c + parser_script.c + seek.c + wind_limits.c + bres_line.c + error.c + intersect.c + mapcase.c + parser_standard_options.c + set_window.c + wind_overlap.c + clicker.c + file_name.c + is.c + mapset.c + parser_wps.c + short_way.c + wind_scan.c + cmprbzip.c + find_etc.c + key_value1.c + mapset_msc.c + paths.c + sleep.c + window_map.c + cmprlz4.c + find_file.c + key_value2.c + mapset_nme.c + percent.c + snprintf.c + worker.c + cmprrle.c + find_rast.c + key_value3.c + mkstemp.c + plot.c + spawn.c + wr_cellhd.c + cmprzlib.c + find_rast3d.c + key_value4.c + myname.c + pole_in_poly.c + strings.c + writ_zeros.c + color_rules.c + find_vect.c + legal_name.c + named_colr.c + popen.c + tempfile.c + xdr.c + color_str.c + compress.c + line_dist.c + nl_to_spaces.c + progrm_nme.c + timestamp.c + zero.c + commas.c + geodesic.c + list.c + nme_in_mps.c + proj1.c + token.c + zone.c + geodist.c + ll_format.c + open.c + proj2.c + trim_dec.c + parser_json.c + cmprzstd.c + compress.c) + +if(MINGW) + list(APPEND gislib_SRCS "fmode.c") +endif() + +set(grass_gis_DEFS "-DGRASS_VERSION_DATE=\"${GRASS_VERSION_DATE}\"") +if(MSVC) + set(grass_gis_DEFS "${grass_gis_DEFS};-D_USE_MATH_DEFINES=1") +endif() + +build_module( + NAME + grass_gis + SOURCES + "${gislib_SRCS}" + DEPENDS + grass_datetime + ZLIB + OPTIONAL_DEPENDS + PTHREAD + BZIP2 + ZSTD + ICONV + REGEX + POSTGRES + DEFS + "${grass_gis_DEFS}") + +add_custom_command( + TARGET grass_gis + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/etc/proj + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/colors + ${GISBASE}/etc/colors/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/ellipse.table + ${GISBASE}/etc/proj/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/datum.table + ${GISBASE}/etc/proj/ + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/datumtransform.table ${GISBASE}/etc/proj/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/FIPS.code + ${GISBASE}/etc/proj/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/state27 + ${GISBASE}/etc/proj/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/state83 + ${GISBASE}/etc/proj/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/projections + ${GISBASE}/etc/proj/ + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/ellipse.table.solar.system ${GISBASE}/etc/proj/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/colors.desc + ${GISBASE}/etc/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/renamed_options + ${GISBASE}/etc/) +install(DIRECTORY colors DESTINATION etc) +install( + FILES ellipse.table + ellipse.table.solar.system + datum.table + datumtransform.table + FIPS.code + state27 + state83 + projections + DESTINATION etc/proj) +install(FILES colors.desc renamed_options DESTINATION etc) + +if(UNIX) + target_link_libraries(grass_gis LIBM) +endif() + +if(MSVC) + target_link_libraries(grass_gis PCRE) +endif() diff --git a/lib/gis/aprintf.c b/lib/gis/aprintf.c index 67cde7f97a5..2c7b235f214 100644 --- a/lib/gis/aprintf.c +++ b/lib/gis/aprintf.c @@ -199,11 +199,11 @@ static int oaprintf(struct options *opts, const char *format, va_list ap) while (*++c && *q != *c) ; if (*c) { - va_list ap_copy; + va_list aq; char tmp; /* copy ap for ovprintf() */ - va_copy(ap_copy, ap); + va_copy(aq, ap); /* found a conversion specifier */ if (*c == 's') { @@ -254,7 +254,7 @@ static int oaprintf(struct options *opts, const char *format, va_list ap) } if (*p_spec) { /* illegal string specifier? */ - va_end(ap_copy); + va_end(aq); *(q + 1) = 0; G_fatal_error( _("Failed to parse string specifier: %s"), p); @@ -290,7 +290,7 @@ static int oaprintf(struct options *opts, const char *format, va_list ap) if (use_ovprintf) { tmp = *(q + 1); *(q + 1) = 0; - nbytes += ovprintf(opts, p, ap_copy); + nbytes += ovprintf(opts, p, aq); *(q + 1) = tmp; } } @@ -298,7 +298,7 @@ static int oaprintf(struct options *opts, const char *format, va_list ap) /* else use ovprintf() for non-string specifiers */ tmp = *(q + 1); *(q + 1) = 0; - nbytes += ovprintf(opts, p, ap_copy); + nbytes += ovprintf(opts, p, aq); *(q + 1) = tmp; /* once ap is passed to another function that calls @@ -345,7 +345,7 @@ static int oaprintf(struct options *opts, const char *format, va_list ap) /* otherwise, no argument is required for m% */ } } - va_end(ap_copy); + va_end(aq); break; } else if (p_spec - spec < SPEC_BUF_SIZE - 2) diff --git a/lib/gis/gisinit.c b/lib/gis/gisinit.c index 8a7d04f0093..9ae04ac2f56 100644 --- a/lib/gis/gisinit.c +++ b/lib/gis/gisinit.c @@ -26,9 +26,25 @@ #include "G.h" #include "gis_local_proto.h" +#ifdef GRASS_CMAKE_BUILD +#include +#else +#define GRASS_GIS_EXPORT +#endif struct G__ G__; -static int initialized = 0; /** Is set when engine is initialized */ +/** initialized is set to 1 when engine is initialized */ +/* GRASS_GIS_EXPORT static int initialized on windows msvc throws below error. +"Error C2201 'initialized': must have external linkage in order to be + exported/imported" +So we do an ifndef on msvc. without GRASS_GIS_EXPORT it will be exported in DLL. +*/ +#ifndef _MSC_VER +static int initialized = 0; +#else +GRASS_GIS_EXPORT int initialized; +#endif + static int gisinit(void); /*! diff --git a/lib/gis/ls_filter.c b/lib/gis/ls_filter.c index 30d98490567..f6dba0319e0 100644 --- a/lib/gis/ls_filter.c +++ b/lib/gis/ls_filter.c @@ -13,10 +13,13 @@ #include #include - #ifdef HAVE_REGEX_H - #include +#endif + +#ifdef HAVE_PCRE_H +#include +#endif struct buffer { char *buf; @@ -143,14 +146,41 @@ static int wc2regex(struct buffer *buf, const char *pat) static int re_filter(const char *filename, void *closure) { +#ifdef HAVE_REGEX_H regex_t *regex = closure; return filename[0] != '.' && regexec(regex, filename, 0, NULL, 0) == 0; +#endif +#ifdef HAVE_PCRE_H + const char *pcreErrorStr; + pcre_extra *pcreExtra; + int pcreExecRet; + pcre *pcre_regex = closure; + + /* Optimize the regex */ + pcreExtra = pcre_study(pcre_regex, 0, &pcreErrorStr); + pcreExecRet = pcre_exec(pcre_regex, pcreExtra, filename, + strlen(filename), /* length of string */ + 0, /* Start looking at this point */ + 0, /* OPTIONS */ + NULL, 0); /* Length of subStrVec */ + + /* Optimize the regex */ + pcreExtra = pcre_study(pcre_regex, 0, &pcreErrorStr); + pcreExecRet = pcre_exec(pcre_regex, pcreExtra, filename, + strlen(filename), /* length of string */ + 0, /* Start looking at this point */ + 0, /* OPTIONS */ + NULL, 0); /* Length of subStrVec */ + + return filename[0] != '.' && pcreExecRet == 0; +#endif } void *G_ls_regex_filter(const char *pat, int exclude, int extended, int ignorecase) { +#ifdef HAVE_REGEX_H regex_t *regex = G_malloc(sizeof(regex_t)); if (regcomp(regex, pat, @@ -166,12 +196,57 @@ void *G_ls_regex_filter(const char *pat, int exclude, int extended, G_set_ls_filter(re_filter, regex); return regex; +#endif + +#ifdef HAVE_PCRE_H + pcre *pcre_regex; + const char *pcreErrorStr; + int pcreErrorOffset; + + /* First, the regex string must be compiled */ + pcre_regex = pcre_compile(pat, 0, &pcreErrorStr, &pcreErrorOffset, NULL); + /* + if (regcomp(regex, pat, REG_NOSUB | + (extended ? REG_EXTENDED : 0) | + (ignorecase ? REG_ICASE : 0)) != 0) { + pcre_free(pcre_regex); + return NULL; + } + */ + if (exclude) + G_set_ls_exclude_filter(re_filter, pcre_regex); + else + G_set_ls_filter(re_filter, pcre_regex); + + /* First, the regex string must be compiled */ + pcre_regex = pcre_compile(pat, 0, &pcreErrorStr, &pcreErrorOffset, NULL); + /* + if (regcomp(regex, pat, REG_NOSUB | + (extended ? REG_EXTENDED : 0) | + (ignorecase ? REG_ICASE : 0)) != 0) { + pcre_free(pcre_regex); + return NULL; + } + */ + if (exclude) + G_set_ls_exclude_filter(re_filter, pcre_regex); + else + G_set_ls_filter(re_filter, pcre_regex); + + return pcre_regex; +#endif } void *G_ls_glob_filter(const char *pat, int exclude, int ignorecase) { struct buffer buf; + +#ifdef HAVE_REGEX_H regex_t *regex; +#endif +#ifdef HAVE_PCRE_H + pcre *pcre_regex; +#endif init(&buf); @@ -179,21 +254,33 @@ void *G_ls_glob_filter(const char *pat, int exclude, int ignorecase) fini(&buf); return NULL; } - +#ifdef HAVE_REGEX_H regex = G_ls_regex_filter(buf.buf, exclude, 1, ignorecase); +#endif +#ifdef HAVE_PCRE_H + pcre_regex = G_ls_regex_filter(buf.buf, exclude, 1, ignorecase); +#endif fini(&buf); +#ifdef HAVE_REGEX_H return regex; +#endif +#ifdef HAVE_PCRE_H + return pcre_regex; +#endif } void G_free_ls_filter(void *regex) { if (!regex) return; - +#ifdef HAVE_REGEX_H regfree(regex); +#endif +#ifdef HAVE_PCRE_H + pcre_free(regex); +#endif + G_free(regex); } - -#endif diff --git a/lib/gis/mapset_msc.c b/lib/gis/mapset_msc.c index 8553ff3807d..2d3351a1393 100644 --- a/lib/gis/mapset_msc.c +++ b/lib/gis/mapset_msc.c @@ -264,7 +264,7 @@ int G__make_mapset_element_misc(const char *dir, const char *name) static int check_owner(const struct stat *info) { -#if defined(__MINGW32__) || defined(SKIP_MAPSET_OWN_CHK) +#if defined(_WIN32) || defined(SKIP_MAPSET_OWN_CHK) return 1; #else const char *check = getenv("GRASS_SKIP_MAPSET_OWNER_CHECK"); diff --git a/lib/gis/parser_interface.c b/lib/gis/parser_interface.c index 735d925ff3c..f3bab3d2aa9 100644 --- a/lib/gis/parser_interface.c +++ b/lib/gis/parser_interface.c @@ -107,16 +107,18 @@ void G__usage_xml(void) char *type; char *s, *top; int i; - const char *encoding; + const char *encoding = ""; int new_prompt = 0; new_prompt = G__uses_new_gisprompt(); /* gettext converts strings to encoding returned by nl_langinfo(CODESET) */ +/* check if local_charset() comes from iconv. If so check for iconv library + * before using it */ #if defined(HAVE_LANGINFO_H) encoding = nl_langinfo(CODESET); -#elif defined(__MINGW32__) && defined(USE_NLS) +#elif defined(_WIN32) && defined(USE_NLS) encoding = locale_charset(); #endif diff --git a/lib/gis/paths.c b/lib/gis/paths.c index a2573762529..047b8d960e9 100644 --- a/lib/gis/paths.c +++ b/lib/gis/paths.c @@ -3,7 +3,7 @@ #include #include -#ifndef __MINGW32__ +#ifndef _WIN32 #include #else #include @@ -26,7 +26,7 @@ int G_mkdir(const char *path) { -#ifdef __MINGW32__ +#ifdef _WIN32 return mkdir(path); #else return mkdir(path, 0777); @@ -62,7 +62,7 @@ int G_is_dirsep(char c) int G_is_absolute_path(const char *path) { if (G_is_dirsep(path[0]) -#ifdef __MINGW32__ +#ifdef _WIN32 || (isalpha(path[0]) && (path[1] == ':') && G_is_dirsep(path[2])) #endif ) @@ -144,7 +144,7 @@ int G_stat(const char *file_name, struct stat *buf) int G_lstat(const char *file_name, struct stat *buf) { -#ifdef __MINGW32__ +#ifdef _WIN32 return stat(file_name, buf); #else return lstat(file_name, buf); @@ -164,7 +164,7 @@ int G_lstat(const char *file_name, struct stat *buf) int G_owner(const char *path) { -#ifndef __MINGW32__ +#ifndef _WIN32 struct stat info; G_stat(path, &info); diff --git a/lib/gis/popen.c b/lib/gis/popen.c index f3e4a2629cf..6b5c9fd07b6 100644 --- a/lib/gis/popen.c +++ b/lib/gis/popen.c @@ -6,7 +6,7 @@ #include #include -#ifdef __MINGW32__ +#ifdef _WIN32 #include #include #define pipe(fds) _pipe(fds, 4096, O_BINARY | O_NOINHERIT) diff --git a/lib/gis/renamed_options b/lib/gis/renamed_options index 965168b29d9..00893c68c83 100644 --- a/lib/gis/renamed_options +++ b/lib/gis/renamed_options @@ -95,6 +95,8 @@ g.mapset|gisdbase:dbase g.mapsets|addmapset:operation g.mapsets|removemapset:operation g.mapsets|measure:method +# g.mkfontcap +g.mkfontcap|-o:--overwrite # g.pnmcomp g.pnmcomp|background:bgcolor ################################### diff --git a/lib/gis/sleep.c b/lib/gis/sleep.c index 8fed1f59ac5..9aad0a973ae 100644 --- a/lib/gis/sleep.c +++ b/lib/gis/sleep.c @@ -1,8 +1,8 @@ #include -#ifndef __MINGW32__ +#ifndef _WIN32 #include #endif -#ifdef __MINGW32__ +#ifdef _WIN32 #include #endif #include @@ -10,7 +10,7 @@ /* Sleep */ void G_sleep(unsigned int seconds) { -#ifdef __MINGW32__ +#ifdef _WIN32 /* note: Sleep() cannot be interrupted */ Sleep((seconds)*1000); #else diff --git a/lib/gis/spawn.c b/lib/gis/spawn.c index d6b5ec72896..1b1630ebc78 100644 --- a/lib/gis/spawn.c +++ b/lib/gis/spawn.c @@ -23,7 +23,7 @@ #include #include -#ifndef __MINGW32__ +#ifndef _WIN32 #include #else #include @@ -68,7 +68,7 @@ struct signal { int action; int signum; int valid; -#ifndef __MINGW32__ +#ifndef _WIN32 struct sigaction old_act; sigset_t old_mask; #endif @@ -95,7 +95,7 @@ struct spawn { static void parse_arglist(struct spawn *sp, va_list va); static void parse_argvec(struct spawn *sp, const char **va); -#ifdef __MINGW32__ +#ifdef _WIN32 struct buffer { char *str; @@ -937,7 +937,7 @@ int G_spawn(const char *command, ...) status = G_spawn_ex(command, -#ifndef __MINGW32__ +#ifndef _WIN32 SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGINT, SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGQUIT, SF_SIGNAL, SST_PRE, SSA_BLOCK, SIGCHLD, #endif @@ -948,7 +948,7 @@ int G_spawn(const char *command, ...) int G_wait(int i_pid) { -#ifdef __MINGW32__ +#ifdef _WIN32 DWORD rights = PROCESS_QUERY_INFORMATION | SYNCHRONIZE; HANDLE hProcess = OpenProcess(rights, FALSE, (DWORD)i_pid); DWORD exitcode; diff --git a/lib/gis/testsuite/gis_lib_env_test.py b/lib/gis/testsuite/gis_lib_env_test.py index 91382f552c0..fafc00a37ed 100644 --- a/lib/gis/testsuite/gis_lib_env_test.py +++ b/lib/gis/testsuite/gis_lib_env_test.py @@ -2,6 +2,7 @@ @author Soeren Gebbert """ + from grass.gunittest.case import TestCase import grass.lib.gis as libgis diff --git a/lib/gis/user_config.c b/lib/gis/user_config.c index 3cebea00934..95a0d75ac07 100644 --- a/lib/gis/user_config.c +++ b/lib/gis/user_config.c @@ -32,7 +32,7 @@ #include #include #include -#ifndef __MINGW32__ +#ifndef _WIN32 #include #endif #include @@ -46,7 +46,7 @@ * path [caller must G_free ()] on success, or NULL on failure *************************************************************************/ -#ifndef __MINGW32__ /* TODO */ +#ifndef _WIN32 /* TODO */ static char *_make_toplevel(void) { size_t len; diff --git a/lib/gis/whoami.c b/lib/gis/whoami.c index d978326b588..4daa35115cc 100644 --- a/lib/gis/whoami.c +++ b/lib/gis/whoami.c @@ -10,11 +10,10 @@ * * \author Original author CERL */ - #include #include -#ifndef __MINGW32__ +#ifndef _WIN32 #include #endif @@ -40,7 +39,7 @@ const char *G_whoami(void) if (G_is_initialized(&initialized)) return name; -#ifdef __MINGW32__ +#ifdef _WIN32 name = getenv("USERNAME"); #endif if (!name || !*name) @@ -49,7 +48,7 @@ const char *G_whoami(void) if (!name || !*name) name = getenv("USER"); -#ifndef __MINGW32__ +#ifndef _WIN32 if (!name || !*name) { struct passwd *p = getpwuid(getuid()); diff --git a/lib/gmath/fft.c b/lib/gmath/fft.c index c0dea7b7d0e..3615fb602b2 100644 --- a/lib/gmath/fft.c +++ b/lib/gmath/fft.c @@ -25,20 +25,16 @@ #include -#if defined(HAVE_FFTW_H) || defined(HAVE_DFFTW_H) || defined(HAVE_FFTW3_H) +#if defined(HAVE_FFTW3_H) || defined(HAVE_FFTW_H) || defined(HAVE_DFFTW_H) -#ifdef HAVE_FFTW_H -#include -#endif - -#ifdef HAVE_DFFTW_H -#include -#endif - -#ifdef HAVE_FFTW3_H +#if defined(HAVE_FFTW3_H) #include #define c_re(c) ((c)[0]) #define c_im(c) ((c)[1]) +#elif defined(HAVE_FFTW_H) +#include +#elif defined(HAVE_DFFTW_H) +#include #endif #include diff --git a/lib/imagery/iscatt_core.c b/lib/imagery/iscatt_core.c index 05ce619eef8..8a3da41d15d 100644 --- a/lib/imagery/iscatt_core.c +++ b/lib/imagery/iscatt_core.c @@ -697,7 +697,6 @@ int I_compute_scatts(struct Cell_head *region, struct scCats *scatt_conds, struct rast_row *bands_rows = G_malloc(n_bands * sizeof(struct rast_row)); RASTER_MAP_TYPE data_type; - int nrows, i_band, n_a_bands, band_id; int i_row, head_nchars, i_cat, id_cat; diff --git a/lib/imagery/testsuite/test_imagery_find.py b/lib/imagery/testsuite/test_imagery_find.py index a943e2d3520..72e99bc2776 100644 --- a/lib/imagery/testsuite/test_imagery_find.py +++ b/lib/imagery/testsuite/test_imagery_find.py @@ -8,6 +8,7 @@ Read the file COPYING that comes with GRASS for details """ + import os import shutil diff --git a/lib/imagery/testsuite/test_imagery_sigfile.py b/lib/imagery/testsuite/test_imagery_sigfile.py index c8bc90a4f95..104cd5a59b4 100644 --- a/lib/imagery/testsuite/test_imagery_sigfile.py +++ b/lib/imagery/testsuite/test_imagery_sigfile.py @@ -8,6 +8,7 @@ Read the file COPYING that comes with GRASS for details """ + import os import stat import ctypes @@ -383,9 +384,9 @@ def test_symmetric_complete_difference(self): self.assertEqual(ref_err, "The_Doors") # Clean up memory to help track memory leaks when run by valgrind - S.semantic_labels[ - 0 - ] = None # C should not call free() on memory allocated by python + S.semantic_labels[0] = ( + None # C should not call free() on memory allocated by python + ) I_free_signatures(ctypes.byref(S)) I_free_group_ref(ctypes.byref(R)) if ret: diff --git a/lib/imagery/testsuite/test_imagery_signature_management.py b/lib/imagery/testsuite/test_imagery_signature_management.py index b2ec954a74e..21f052372e2 100644 --- a/lib/imagery/testsuite/test_imagery_signature_management.py +++ b/lib/imagery/testsuite/test_imagery_signature_management.py @@ -8,6 +8,7 @@ Read the file COPYING that comes with GRASS for details """ + import os import shutil import ctypes diff --git a/lib/imagery/testsuite/test_imagery_sigsetfile.py b/lib/imagery/testsuite/test_imagery_sigsetfile.py index 6e5a119c236..b8bcb566520 100644 --- a/lib/imagery/testsuite/test_imagery_sigsetfile.py +++ b/lib/imagery/testsuite/test_imagery_sigsetfile.py @@ -8,6 +8,7 @@ Read the file COPYING that comes with GRASS for details """ + import os import stat import ctypes diff --git a/lib/init/CMakeLists.txt b/lib/init/CMakeLists.txt new file mode 100644 index 00000000000..ba18ea68045 --- /dev/null +++ b/lib/init/CMakeLists.txt @@ -0,0 +1,239 @@ +# #for i18N support + +file(GLOB init_HTMLFILES "*.html") + +# START_UP is the variable used in grass.py, grass.sh.in and grass.bat.in +set(START_UP "grass${GRASS_VERSION_MAJOR}${GRASS_VERSION_MINOR}.py") +if(WIN32) + set(script_file_name "grass.bat") + set(script_input_file_name ${script_file_name}.in) +else() + set(script_file_name "grass") + set(script_input_file_name ${script_file_name}.sh.in) +endif() + +file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR}/bin BINARY_DIR) + +set(CONFIG_PROJSHARE) +get_filename_component(PROJ_INSTALL_PREFIX ${PROJ_INCLUDE_DIR} PATH) +if(DEFINED ENV{PROJSHARE}) + message(WARNING "External PROJ directory not specified; default will be used") + set(CONFIG_PROJSHARE "$ENV{PROJSHARE}") +else() + set(CONFIG_PROJSHARE "${PROJ_INSTALL_PREFIX}/share/proj") + if(EXISTS ${CONFIG_PROJSHARE}/epsg) + message(STATUS "PROJ directory ${CONFIG_PROJSHARE}") + endif() +endif() +file(TO_NATIVE_PATH "${PROJ_INSTALL_PREFIX}/share/proj" PROJ_LIB) +file(TO_NATIVE_PATH ${CONFIG_PROJSHARE} GRASS_PROJSHARE) + +find_path(gdal_share_dir "gdal" PATH_SUFFIXES share) +if(NOT gdal_share_dir) + message(FATAL_ERROR "Cannot find share/gdal") +endif() +mark_as_advanced(gdal_share_dir) + +file(TO_NATIVE_PATH "${gdal_share_dir}/gdal" GDAL_DATA) + +if(MSVC) + find_path(geotiff_share_dir "epsg_csv" PATH_SUFFIXES share) + mark_as_advanced(geotiff_share_dir) + if(geotiff_share_dir) + file(TO_NATIVE_PATH "${geotiff_share_dir}/epsg_csv" GEOTIFF_CSV) + else() + message(FATAL_ERROR "Cannot find share/epsg_csv.") + endif() +endif() # MSVC + +get_filename_component(GDAL_DIR ${GDAL_LIBRARY} PATH) +get_filename_component(GDAL_DIR ${GDAL_DIR} PATH) + +file(TO_NATIVE_PATH ${GDAL_DIR}/bin DEPS_DLL_PATH) +list(APPEND DLL_PATH_LIST ${DEPS_DLL_PATH}) + +file(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} GRASS_PYTHON) + +# For install tree (first do install tree) +if(UNIX OR MINGW) + if(DEFINED ENV{LD_LIBRARY_PATH}) + set(LD_LIBRARY_PATH_VAR "${CMAKE_INSTALL_PREFIX}/lib:$ENV{LD_LIBRARY_PATH}") + else() + set(LD_LIBRARY_PATH_VAR "${CMAKE_INSTALL_PREFIX}/lib") + endif() +endif() + +if(WIN32) + set(app_data_dir $ENV{APPDATA}) + if(NOT EXISTS ${app_data_dir}) + # this can happen with some strange settings + message( + FATAL_ERROR + "The APPDATA variable is not set, ask your operating system support") + endif() + file(TO_NATIVE_PATH "${app_data_dir}/GRASS8" grass_config_dir) +else() + set(grass_config_dir "$ENV{HOME}/.grass8") +endif() + +file(TO_NATIVE_PATH "${CMAKE_INSTALL_PREFIX}" gisbase_init_dir) +message(STATUS "GISBASE (install) : ${gisbase_init_dir}") +message(STATUS "grass config directory (install): ${grass_config_dir}") + +# configure and install env.sh +if(NOT MSVC) + configure_file(env.sh ${CMAKE_CURRENT_BINARY_DIR}/bashrc @ONLY) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/bashrc + DESTINATION ${grass_config_dir}) +endif() + +# configure and install grass.py +configure_file(grass.py ${CMAKE_CURRENT_BINARY_DIR}/etc/${START_UP} @ONLY) +install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/etc/${START_UP} DESTINATION etc) + +# configure and install grass wrapper script (grass.bat or grass.sh +configure_file(${script_input_file_name} + ${CMAKE_CURRENT_BINARY_DIR}/${script_file_name} @ONLY) +install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${script_file_name} + DESTINATION bin) + +# For build tree +file(TO_NATIVE_PATH ${GISBASE} gisbase_init_dir) +file(TO_NATIVE_PATH "${GISBASE}/etc/config" grass_config_dir) + +if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + configure_file( + ${script_input_file_name} + ${GISBASE}/${script_file_name} + FILE_PERMISSIONS + OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE + @ONLY) +else() + configure_file(${script_input_file_name} ${GISBASE}/${script_file_name} @ONLY) + if(UNIX OR MINGW) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19) + file( + CHMOD + ${GISBASE}/${script_file_name} + FILE_PERMISSIONS + OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE) + else() + execute_process(COMMAND /bin/chmod 755 ${GISBASE}/${script_file_name}) + endif() + endif() +endif() + +file(COPY ${CMAKE_SOURCE_DIR}/demolocation/PERMANENT + DESTINATION ${GISBASE}/demolocation/) + +configure_file(${CMAKE_SOURCE_DIR}/demolocation/grassrc.cmake.in + "${grass_config_dir}/rc" @ONLY) + +file(TO_NATIVE_PATH ${GISBASE}/bin grass_dll_dir) +set(DLL_PATH_LIST) +list(APPEND DLL_PATH_LIST ${grass_dll_dir}) +separate_arguments(DLL_PATH_LIST) + +set(LD_LIBRARY_PATH_VAR) +if(UNIX OR MINGW) + if(DEFINED ENV{LD_LIBRARY_PATH}) + set(LD_LIBRARY_PATH_VAR "${GISBASE}/lib:$ENV{LD_LIBRARY_PATH}") + else() + set(LD_LIBRARY_PATH_VAR "${GISBASE}/lib") + endif() +endif() +message(STATUS "GISBASE (build) : ${gisbase_init_dir}") +message(STATUS "grass config directory (build): ${grass_config_dir}") +if(NOT MSVC) + configure_file(env.sh ${grass_config_dir}/bashrc @ONLY) + message(STATUS "env variables: ${GISBASE}/etc/config/bashrc") +endif() + +configure_file(grass.py ${GISBASE}/etc/${START_UP} @ONLY) +message(STATUS "Startup (build): ${GISBASE}/${script_file_name}") +message(STATUS "gisrc (build): ${GISBASE}/etc/config/rc") + +# finish installtree and buildtree configurations + +build_program( + NAME + echo + SOURCES + echo.c + PACKAGE + "grasslibs" + RUNTIME_OUTPUT_DIR + etc) + +build_program( + NAME + run + SOURCES + run.c + PACKAGE + "grasslibs" + RUNTIME_OUTPUT_DIR + etc) + +build_program( + NAME + clean_temp + SOURCES + clean_temp.c + DEPENDS + grass_gis + PACKAGE + "grasslibs" + RUNTIME_OUTPUT_DIR + etc) + +build_program( + NAME + lock + SOURCES + lock.c + DEPENDS + grass_gis + grass_datetime + PACKAGE + "grasslibs" + RUNTIME_OUTPUT_DIR + etc) + +if(MINGW) + build_program(NAME winlocale SOURCES winlocale.c RUNTIME_OUTPUT_DIR etc) +endif() + +set(VERSIONNUMBER_CONTENTS "${GRASS_VERSION_NUMBER}") +if(GRASS_VERSION_GIT) + list(APPEND VERSIONNUMBER_CONTENTS + "${VERSIONNUMBER_CONTENTS} ${GRASS_VERSION_GIT}") +endif() + +file(WRITE ${CMAKE_BINARY_DIR}/gisbase/etc/VERSIONNUMBER + "${VERSIONNUMBER_CONTENTS}") +install(FILES ${CMAKE_BINARY_DIR}/gisbase/etc/VERSIONNUMBER DESTINATION etc) + +configure_file(license.txt.in ${CMAKE_BINARY_DIR}/gisbase/etc/license) + +install(FILES ${CMAKE_BINARY_DIR}/gisbase/etc/VERSIONNUMBER DESTINATION etc) +install(FILES ${CMAKE_BINARY_DIR}/gisbase/etc/license DESTINATION etc) +install(FILES ${CMAKE_BINARY_DIR}/gisbase/etc/lock DESTINATION etc) +install(FILES ${CMAKE_BINARY_DIR}/gisbase/etc/echo DESTINATION etc) +install(FILES ${CMAKE_BINARY_DIR}/gisbase/etc/run DESTINATION etc) +install(FILES ${CMAKE_BINARY_DIR}/gisbase/etc/clean_temp DESTINATION etc) +if(MINGW) + install(FILES ${CMAKE_BINARY_DIR}/gisbase/etc/winlocale DESTINATION etc) +endif() diff --git a/lib/init/clean_temp.c b/lib/init/clean_temp.c index aa6301c531e..eeb340b1879 100644 --- a/lib/init/clean_temp.c +++ b/lib/init/clean_temp.c @@ -35,7 +35,6 @@ #define SLEEP 30 /* 30 seconds */ /* Recursively scan the directory pathname, removing directory and files */ - void clean_dir(const char *pathname, uid_t uid, pid_t pid, time_t now, int max_age) { @@ -139,7 +138,7 @@ int main(int argc, char *argv[]) G_file_name(tmppath, element, "", mapset = G_mapset()); /* get user id and current time in seconds */ -#ifdef __MINGW32__ +#ifdef _WIN32 /* TODO */ uid = -1; #else @@ -171,7 +170,7 @@ int main(int argc, char *argv[]) int find_process(int pid) { -#ifdef __MINGW32__ +#ifdef _WIN32 /* TODO */ return -1; #else diff --git a/lib/init/env.sh b/lib/init/env.sh new file mode 100644 index 00000000000..95eff198af5 --- /dev/null +++ b/lib/init/env.sh @@ -0,0 +1,10 @@ +export GRASS_PROJSHARE=@GRASS_PROJSHARE@ +export PROJ_LIB=@PROJ_LIB@ +export GDAL_DATA=@GDAL_DATA@ +export GISBASE=@gisbase_init_dir@ +export GRASS_PYTHON=@GRASS_PYTHON@ +export GRASS_CONFIG_DIR=@grass_config_dir@ + +# export PYTHONHOME=$gisbase_init_dir\Python37 +# export FONTCONFIG_FILE=@gisbase_init_dir@\etc\fonts.conf +# export LD_LIBRARY_PATH=@DLL_PATH_LIST@:PATH% diff --git a/lib/init/grass.bat.in b/lib/init/grass.bat.in new file mode 100644 index 00000000000..cb95984ee55 --- /dev/null +++ b/lib/init/grass.bat.in @@ -0,0 +1,29 @@ +@echo off +::set PYTHONHOME=%GISBASE%\Python37 + +set GRASS_PROJSHARE=@GRASS_PROJSHARE@ + +set PROJ_LIB=@PROJ_LIB@ + +set GDAL_DATA=@GDAL_DATA@ + +set GEOTIFF_CSV=@GEOTIFF_CSV@ + +::set FONTCONFIG_FILE=%GISBASE%\etc\fonts.conf + +set PATH=@gisbase_init_dir@\bin;@BINARY_DIR@;@DLL_PATH_LIST@;%PATH% + +set GISBASE=@gisbase_init_dir@ + +set PYTHONPATH=@gisbase_init_dir@\etc\python;@gisbase_init_dir@\gui\wxpython;@gisbase_init_dir@\etc + +set GRASS_PYTHON=@GRASS_PYTHON@ + +set GRASS_CONFIG_DIR=@grass_config_dir@ + +"@GRASS_PYTHON@" "@gisbase_init_dir@\etc\@START_UP@" %* + +rem +rem Pause on error +rem +if %ERRORLEVEL% GEQ 1 pause diff --git a/lib/init/grass.html b/lib/init/grass.html index b80cb319338..5b2d918fb12 100644 --- a/lib/init/grass.html +++ b/lib/init/grass.html @@ -5,8 +5,8 @@

SYNOPSIS

grass [-h | -help | --help] [-v | --version] | [-c | -c geofile | -c EPSG:code[:datum_trans]] | -e | -f | [--text | --gtext | --gui] | --config | -[--tmp-location | --tmp-mapset] - [[[<GISDBASE>/]<LOCATION>/] +[--tmp-project | --tmp-mapset] + [[[<GISDBASE>/]<PROJECT>/] <MAPSET>] [--exec EXECUTABLE] @@ -20,20 +20,20 @@

Flags:

-v | --version
Prints the version of GRASS and exits -
-c -
Creates new GRASS unprojected location in specified GISDBASE +
-c XY +
Creates new GRASS project (location) without coordinate reference system in specified GISDBASE
-c geofile -
Creates new GRASS projected location in specified GISDBASE based on georeferenced file +
Creates new GRASS project in specified GISDBASE with coordinate reference system based on georeferenced file
-c EPSG:code -
Creates new GRASS projected location in specified GISDBASE with given EPSG code +
Creates new GRASS project in specified GISDBASE with coordinate reference system defined by EPSG code
-c EPSG:code:datum_trans -
Creates new GRASS projected location in specified GISDBASE with given EPSG code and datum transform parameters +
Creates new GRASS project in specified GISDBASE with coordinate reference system defined by EPSG code and datum transform parameters
-e -
Exit after creation of location or mapset. Only with -c flag +
Exit after creation of project or mapset. Only with -c flag
-f
Forces removal of .gislock if exists (use with care!). Only with --text flag @@ -54,15 +54,15 @@

Flags:

--exec EXECUTABLE
Execute GRASS module or script. The provided executable will be executed in a GRASS GIS non-interactive session. -
--tmp-location -
Run using a temporary location which is created based on the given +
--tmp-project +
Run using a temporary project which is created based on the given coordinate reference system and deleted at the end of the execution (use with the --exec flag). The active mapset will be the PERMANENT mapset.
--tmp-mapset
Run using a temporary mapset which is created in the specified -location and deleted at the end of the execution +project and deleted at the end of the execution (use with the --exec flag). @@ -74,11 +74,12 @@

Parameters:

Initial database directory which should be a fully qualified path (e.g., /usr/local/share/grassdata) -
LOCATION -
Initial location directory which is a subdirectory of GISDBASE +
PROJECT +
Initial project directory which is a subdirectory of GISDBASE + (project was previously called location)
MAPSET -
Initial mapset directory which is a subdirectory of LOCATION +
Initial mapset directory which is a subdirectory of PROJECT Note: These parameters must be specified in one of the @@ -86,8 +87,8 @@

Parameters:

     MAPSET
-    LOCATION/MAPSET
-    GISDBASE/LOCATION/MAPSET
+    PROJECT/MAPSET
+    GISDBASE/PROJECT/MAPSET
 

DESCRIPTION

@@ -130,18 +131,18 @@

Config flag

  • arch: system architecture (e.g., x86_64-pc-linux-gnu)
  • build: (e.g., ./configure --with-cxx --enable-largefile --with-proj [...])
  • compiler: (e.g., gcc)
  • -
  • date: (e.g., Tue Mar 31 20:34:57 2020 +0200)
  • +
  • date: (e.g., 2024-04-10T11:44:54+00:00)
  • path: (e.g., /usr/lib64/grass)
  • python_path: (e.g., /usr/lib64/grass/etc/python)
  • revision: (e.g., 745ee7ec9)
  • svn_revision: (e.g., 062bffc8)
  • -
  • version: (e.g., 8.2.0dev)
  • +
  • version: (e.g., 8.4.0)
  • SAMPLE DATA

    The GRASS GIS project provides several free sample geospatial datasets -as ready-to-use locations. They are available to download at +as ready-to-use projects. They are available to download at https://grass.osgeo.org/download/sample-data/. The "North Carolina data set" is a modern package of geospatial data from @@ -247,20 +248,20 @@

    EXAMPLES

    grass
    Start GRASS using the default user interface. The user will be - prompted to choose the appropriate location and mapset. + prompted to choose the appropriate project and mapset.
    grass --gui
    Start GRASS using the graphical user interface. The user will be - prompted to choose the appropriate location and mapset. + prompted to choose the appropriate project and mapset.
    grass --text
    Start GRASS using the text-based user interface. Appropriate -location and mapset must be set by environmental variables (see +project and mapset must be set by environmental variables (see examples below) otherwise taken from the last GRASS session.
    grass --gtext
    Start GRASS using the text-based user interface. The user will be - prompted to choose the appropriate location and mapset. + prompted to choose the appropriate project and mapset.
    grass $HOME/grassdata/spearfish70/user1
    Start GRASS using the default user interface and automatically @@ -268,27 +269,27 @@

    EXAMPLES

    grass --gui -
    Start GRASS using the graphical user interface and try to - obtain the location and mapset from environment variables. + obtain the project and mapset from environment variables. -
    grass -c EPSG:4326 $HOME/grassdata/mylocation -
    Creates a new GRASS location with EPSG code 4326 (latitude-longitude, WGS84) +
    grass -c EPSG:4326 $HOME/grassdata/myproject +
    Creates a new GRASS project with EPSG code 4326 (latitude-longitude, WGS84) in the specified GISDBASE -
    grass -c EPSG:5514:3 $HOME/grassdata/mylocation -
    Creates a new GRASS location with EPSG code 5514 (S-JTSK / Krovak +
    grass -c EPSG:5514:3 $HOME/grassdata/myproject +
    Creates a new GRASS project with EPSG code 5514 (S-JTSK / Krovak East North - SJTSK) with datum transformation parameters used in Czech Republic in the specified GISDBASE
    grass -c XY $HOME/grassdata/gnomonic --exec g.proj -c proj4='+proj=gnom +lat_0=90 +lon_0=-50' -
    Creates a new GRASS location from PROJ definition string +
    Creates a new GRASS project from PROJ definition string (here: gnomonic) in the specified GISDBASE -
    grass -c myvector.shp $HOME/grassdata/mylocation -
    Creates a new GRASS location based on georeferenced Shapefile +
    grass -c myvector.shp $HOME/grassdata/myproject +
    Creates a new GRASS project based on georeferenced Shapefile -
    grass -c myraster.tif $HOME/grassdata/mylocation -
    Creates a new GRASS location based on georeferenced GeoTIFF file +
    grass -c myraster.tif $HOME/grassdata/myproject +
    Creates a new GRASS project based on georeferenced GeoTIFF file

    Batch jobs with the exec interface

    @@ -300,7 +301,7 @@

    Batch jobs with the exec interface

    Region issues ignored. --> -Creating a new Location based on a geodata file's projection (-c) +Creating a new project based on a geodata file's projection (-c) and exit (-e) immediately:
    @@ -374,45 +375,45 @@ 

    Execution of shell and Python scripts instead of single commands

    print(vector)
    -

    Using temporary location

    +

    Using temporary project

    -Creating a new temporary location based on a georeferenced file's -projection coordinate reference system (CRS) and simultaneously starting +Creating a new temporary project based on a georeferenced file's +coordinate reference system (CRS) and simultaneously starting computation in a shell script:
    -grass --tmp-location elevation.tiff --exec test.sh
    +grass --tmp-project elevation.tiff --exec test.sh
     
    The same, but using an EPSG code and a Python script:
    -grass --tmp-location EPSG:3358 --exec test.py
    +grass --tmp-project EPSG:3358 --exec test.py
     
    -Finally, for special cases, we can create an XY location without any CRS: +Finally, for special cases, we can create an XY project without any CRS:
    -grass --tmp-location XY --exec test.py
    +grass --tmp-project XY --exec test.py
     
    -Temporary location is automatically deleted after computation, +Temporary project is automatically deleted after computation, so the script is expected to export, link or otherwise preserve the output data before ending.

    A single command can be also executed, e.g. to examine properties of the -temporary location: +temporary project:

    -grass --tmp-location EPSG:3358 --exec g.proj -p
    +grass --tmp-project EPSG:3358 --exec g.proj -p
     
    -A temporary XY location with single command is useful, e.g. to show +A temporary XY project with single command is useful, e.g. to show help text of a module:
    -grass --tmp-location XY --exec r.neighbors --help
    +grass --tmp-project XY --exec r.neighbors --help
     
    @@ -420,7 +421,7 @@

    Using temporary mapset

    A single command can be executed, e.g., to examine properties of a -location (here using the NC SPM sample location): +project (here using the NC SPM sample dataset):

     grass --tmp-mapset /path/to/grassdata/nc_spm_08/ --exec g.proj -p
    diff --git a/lib/init/grass.py b/lib/init/grass.py
    index b29d638d116..6d9d8b3b3e1 100755
    --- a/lib/init/grass.py
    +++ b/lib/init/grass.py
    @@ -309,10 +309,10 @@ def f(fmt, *args):
       $CMD_NAME [-h | --help] [-v | --version]
               [-c | -c geofile | -c EPSG:code[:datum_trans] | -c XY]
               [-e] [-f] [--text | --gtext | --gui] [--config param]
    -          [[[GISDBASE/]LOCATION/]MAPSET]
    -  $CMD_NAME [FLAG]... GISDBASE/LOCATION/MAPSET --exec EXECUTABLE [EPARAM]...
    -  $CMD_NAME --tmp-location [geofile | EPSG | XY] --exec EXECUTABLE [EPARAM]...
    -  $CMD_NAME --tmp-mapset GISDBASE/LOCATION/ --exec EXECUTABLE [EPARAM]...
    +          [[[GISDBASE/]PROJECT/]MAPSET]
    +  $CMD_NAME [FLAG]... GISDBASE/PROJECT/MAPSET --exec EXECUTABLE [EPARAM]...
    +  $CMD_NAME --tmp-project [geofile | EPSG | XY] --exec EXECUTABLE [EPARAM]...
    +  $CMD_NAME --tmp-mapset GISDBASE/PROJECT/ --exec EXECUTABLE [EPARAM]...
     
     {flags}:
       -h or --help                   {help_flag}
    @@ -330,6 +330,8 @@ def f(fmt, *args):
                                        {config_detail}
       --exec EXECUTABLE              {exec_}
                                        {exec_detail}
    +  --tmp-project                  {tmp_project}
    +                                   {tmp_project_detail}
       --tmp-location                 {tmp_location}
                                        {tmp_location_detail}
       --tmp-mapset                   {tmp_mapset}
    @@ -338,11 +340,11 @@ def f(fmt, *args):
     {params}:
       GISDBASE                       {gisdbase}
                                        {gisdbase_detail}
    -  LOCATION                       {location}
    -                                   {location_detail}
    +  PROJECT                        {project}
    +                                   {project_detail}
       MAPSET                         {mapset}
     
    -  GISDBASE/LOCATION/MAPSET       {full_mapset}
    +  GISDBASE/PROJECT/MAPSET        {full_mapset}
     
       EXECUTABLE                     {executable}
       EPARAM                         {executable_params}
    @@ -364,10 +366,8 @@ def help_message(default_gui):
                 flags=_("Flags"),
                 help_flag=_("print this help message"),
                 version_flag=_("show version information and exit"),
    -            create=_("create given database, location or mapset if it doesn't exist"),
    -            exit_after=_(
    -                "exit after creation of location or mapset. Only with -c flag"
    -            ),
    +            create=_("create given database, project or mapset if it doesn't exist"),
    +            exit_after=_("exit after creation of project or mapset. Only with -c flag"),
                 force_removal=_(
                     "force removal of .gislock if exists (use with care!)."
                     " Only with --text flag"
    @@ -380,18 +380,19 @@ def help_message(default_gui):
                 gui_detail=_("and set as default"),
                 config=_("print GRASS configuration parameters"),
                 config_detail=_(
    -                "options: arch,build,compiler,date,path,python_path,revision,svn_revision,version"
    +                "options: arch,build,compiler,date,path,python_path,revision,"
    +                "svn_revision,version"
                 ),
                 params=_("Parameters"),
                 gisdbase=_("initial GRASS database directory"),
    -            gisdbase_detail=_("directory containing Locations"),
    -            location=_("initial GRASS Location"),
    -            location_detail=_(
    -                "directory containing Mapsets with one common"
    -                " coordinate system (projection)"
    +            gisdbase_detail=_("directory containing GRASS projects"),
    +            project=_("initial GRASS project (location)"),
    +            project_detail=_(
    +                "directory containing mapsets with one common"
    +                " coordinate reference system"
                 ),
    -            mapset=_("initial GRASS Mapset"),
    -            full_mapset=_("fully qualified initial Mapset directory"),
    +            mapset=_("initial GRASS mapset"),
    +            full_mapset=_("fully qualified initial mapset directory"),
                 env_vars=_("Environment variables relevant for startup"),
                 gui_var=_("select GUI (text, gui, gtext)"),
                 html_var=_("set html web browser for help pages"),
    @@ -407,14 +408,14 @@ def help_message(default_gui):
                 executable=_("GRASS module, script or any other executable"),
                 executable_params=_("parameters of the executable"),
                 standard_flags=_("standard flags"),
    -            tmp_location=_("create temporary location (use with the --exec flag)"),
    -            tmp_location_detail=_(
    +            tmp_location=_("deprecated, use --tmp-project instead"),
    +            tmp_location_detail=_("location was renamed to project"),
    +            tmp_project=_("create temporary project (use with the --exec flag)"),
    +            tmp_project_detail=_(
                     "created in a temporary directory and deleted at exit"
                 ),
                 tmp_mapset=_("create temporary mapset (use with the --exec flag)"),
    -            tmp_mapset_detail=_(
    -                "created in the specified location and deleted at exit"
    -            ),
    +            tmp_mapset_detail=_("created in the specified project and deleted at exit"),
             )
         )
         s = t.substitute(
    @@ -985,23 +986,23 @@ def cannot_create_location_reason(gisdbase, location):
         path = os.path.join(gisdbase, location)
         if is_location_valid(gisdbase, location):
             return _(
    -            "Unable to create new location because"
    -            " the location <{location}>"
    +            "Unable to create new project because"
    +            " the project <{location}>"
                 " already exists."
             ).format(**locals())
         elif os.path.isfile(path):
             return _(
    -            "Unable to create new location <{location}> because" " <{path}> is a file."
    +            "Unable to create new project <{location}> because" " <{path}> is a file."
             ).format(**locals())
         elif os.path.isdir(path):
             return _(
    -            "Unable to create new location <{location}> because"
    +            "Unable to create new project <{location}> because"
                 " the directory <{path}>"
                 " already exists."
             ).format(**locals())
         else:
             return _(
    -            "Unable to create new location in"
    +            "Unable to create new project in"
                 " the directory <{path}>"
                 " for an unknown reason."
             ).format(**locals())
    @@ -1064,11 +1065,11 @@ def set_mapset(
             # set gisdbase to temporary directory
             gisdbase = tmpdir
             # we are already in a unique directory, so we can use fixed name
    -        location_name = "tmploc"
    +        location_name = "tmpproject"
             # we need only one mapset
             mapset = "PERMANENT"
             debug(
    -            "Using temporary location <{gdb}{sep}{lc}>".format(
    +            "Using temporary project <{gdb}{sep}{lc}>".format(
                     gdb=gisdbase, lc=location_name, sep=os.path.sep
                 )
             )
    @@ -1129,11 +1130,11 @@ def set_mapset(
                             fatal(cannot_create_location_reason(gisdbase, location_name))
                         # create new location based on the provided EPSG/...
                         if not geofile:
    -                        fatal(_("Provide CRS to create a location"))
    +                        fatal(_("Provide CRS to create a project"))
                         if not tmp_location:
                             # Report report only when new location is not temporary.
                             message(
    -                            _("Creating new GRASS GIS location <{}>...").format(
    +                            _("Creating new GRASS GIS project <{}>...").format(
                                     location_name
                                 )
                             )
    @@ -1167,7 +1168,7 @@ def set_mapset(
                                     _(
                                         "No CRS is needed for creating mapset <{mapset}>, "
                                         "but <{geofile}> was provided as CRS."
    -                                    " Did you mean to create a new location?"
    +                                    " Did you mean to create a new project?"
                                     ).format(mapset=mapset, geofile=geofile)
                                 )
                             if not tmp_mapset:
    @@ -1203,7 +1204,7 @@ def set_mapset(
         else:
             fatal(
                 _(
    -                "GRASS GIS database directory, location and mapset"
    +                "GRASS GIS database directory, project and mapset"
                     " not set properly."
                     " Use GUI or command line to set them."
                 )
    @@ -1492,8 +1493,10 @@ def set_language(grass_config_dir):
                             # If we got so far, attempts to set up language and locale have
                             # failed on this system.
                             sys.stderr.write(
    -                            "Failed to enforce user specified language '%s' with error: '%s'\n"
    -                            % (language, e)
    +                            (
    +                                "Failed to enforce user specified language "
    +                                f"'{language}' with error: '{e}'\n"
    +                            )
                             )
                             sys.stderr.write(
                                 "A LANGUAGE environmental variable has been set.\n"
    @@ -1908,7 +1911,7 @@ def csh_startup(location, grass_env_file):
     
         f.write("alias _location g.gisenv get=LOCATION_NAME\n")
         f.write("alias _mapset g.gisenv get=MAPSET\n")
    -    f.write("alias precmd 'echo \"Mapset <`_mapset`> in Location <`_location`>\"'\n")
    +    f.write("alias precmd 'echo \"Mapset <`_mapset`> in project <`_location`>\"'\n")
         f.write('set prompt="GRASS > "\n')
     
         # csh shell rc file left for backward compatibility
    @@ -2282,7 +2285,7 @@ def add_mapset_arguments(parser, mapset_as_option):
                 "--tmp-mapset",
                 metavar="PATH",
                 type=str,
    -            help=_("use temporary mapset in location %(metavar)s"),
    +            help=_("use temporary mapset in project %(metavar)s"),
             )
         else:
             parser.add_argument(
    @@ -2290,19 +2293,25 @@ def add_mapset_arguments(parser, mapset_as_option):
                 metavar="PATH",
                 type=str,
                 nargs="?",
    -            help=_("path to mapset (or location if creating one)"),
    +            help=_("path to mapset (or project if creating one)"),
             )
             parser.add_argument(
                 "--tmp-mapset", action="store_true", help=_("use temporary mapset")
             )
         parser.add_argument(
    -        "--tmp-location",
    +        "--tmp-project",
             metavar="CRS",
             type=str,
             help=_(
    -            "use temporary location with %(metavar)s (EPSG, georeferenced file, ...)"
    +            "use temporary project with %(metavar)s (EPSG, georeferenced file, ...)"
             ),
         )
    +    parser.add_argument(
    +        "--tmp-location",
    +        metavar="CRS",
    +        type=str,
    +        help=_("deprecated, use --tmp-project instead"),
    +    )
         parser.add_argument(
             "-f",
             "--force-remove-lock",
    @@ -2318,6 +2327,13 @@ def update_params_with_mapset_arguments(params, args):
         if args.tmp_location:
             params.tmp_location = True
             params.geofile = args.tmp_location
    +        sys.stdout.write(
    +            _("Option --tmp-location is deprecated, use --tmp-project instead\n")
    +        )
    +        sys.stdout.flush()
    +    if args.tmp_project:
    +        params.tmp_location = True
    +        params.geofile = args.tmp_project
         if args.tmp_mapset:
             params.tmp_mapset = True
         if args.mapset:
    @@ -2414,10 +2430,10 @@ def validate_cmdline(params):
         if params.exit_grass and not params.create_new:
             fatal(_("Flag -e requires also flag -c"))
         if params.create_new and not params.mapset:
    -        fatal(_("Flag -c requires name of location or mapset"))
    +        fatal(_("Flag -c requires name of project or mapset"))
         if params.tmp_location and params.tmp_mapset:
             fatal(
    -            _("Either --tmp-location or --tmp-mapset can be used, not both").format(
    +            _("Either --tmp-project or --tmp-mapset can be used, not both").format(
                     params.mapset
                 )
             )
    @@ -2425,14 +2441,14 @@ def validate_cmdline(params):
             fatal(
                 _(
                     "Coordinate reference system argument (e.g. EPSG)"
    -                " is needed for --tmp-location"
    +                " is needed for --tmp-project"
                 )
             )
         if params.tmp_location and params.mapset:
             fatal(
                 _(
                     "Only one argument (e.g. EPSG) is needed for"
    -                " --tmp-location, mapset name <{}> provided"
    +                " --tmp-project, mapset name <{}> provided"
                 ).format(params.mapset)
             )
         # For now, we allow, but not advertise/document, --tmp-location
    @@ -2530,12 +2546,12 @@ def main():
                         " the '--gui' switch\n"
                         "     {cmd_name} --gui\n"
                         " - Launch with path to "
    -                    "the location/mapset as an argument\n"
    -                    "     {cmd_name} /path/to/location/mapset`\n"
    -                    " - Create a location with '-c' and launch in its"
    +                    "the project/mapset as an argument\n"
    +                    "     {cmd_name} /path/to/project/mapset`\n"
    +                    " - Create a project with '-c' and launch in its"
                         " PERMANENT mapset\n"
    -                    "     {cmd_name} -c EPSG:number /path/to/location\n"
    -                    "     {cmd_name} -c geofile /path/to/location\n"
    +                    "     {cmd_name} -c EPSG:number /path/to/project\n"
    +                    "     {cmd_name} -c geofile /path/to/project\n"
                         " - Create manually the GISRC file ({gisrcrc})\n"
                         " - Use '--help' for further options\n"
                         "     {cmd_name} --help\n"
    @@ -2602,7 +2618,7 @@ def main():
                     elif not default_location:
                         fatal(
                             _(
    -                            "Failed to start GRASS GIS, no default location to copy in"
    +                            "Failed to start GRASS GIS, no default project to copy in"
                                 " the installation or copying failed."
                             )
                         )
    diff --git a/lib/init/grass.sh.in b/lib/init/grass.sh.in
    new file mode 100644
    index 00000000000..a37f5b2e624
    --- /dev/null
    +++ b/lib/init/grass.sh.in
    @@ -0,0 +1,6 @@
    +#! /bin/sh
    +trap "echo 'User break!' ; exit" 2 3 9 15
    +
    +. @grass_config_dir@/bashrc
    +
    +"$GRASS_PYTHON" "@gisbase_init_dir@/etc/@START_UP@" "$@"
    diff --git a/lib/init/license.txt.in b/lib/init/license.txt.in
    new file mode 100644
    index 00000000000..c65922aa07e
    --- /dev/null
    +++ b/lib/init/license.txt.in
    @@ -0,0 +1,11 @@
    +Geographic Resources Analysis Support System (GRASS) is Copyright,
    +1999-@GRASS_VERSION_DATE@ by the GRASS Development Team, and licensed under terms of the
    +GNU General Public License (GPL) version >=2.
    +
    +This GRASS GIS @GRASS_VERSION_NUMBER@ release is coordinated and produced by
    +the GRASS Development Team with contributions from all over the world.
    +
    +This program is distributed in the hope that it will be useful, but
    +WITHOUT ANY WARRANTY; without even the implied warranty of
    +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    +General Public License for more details.
    diff --git a/lib/init/lock.c b/lib/init/lock.c
    index a1dc8ca93e5..7d435c0878a 100644
    --- a/lib/init/lock.c
    +++ b/lib/init/lock.c
    @@ -38,7 +38,7 @@ int main(int argc, char *argv[])
             G_fatal_error(_("Usage: %s file pid"), argv[0]);
     #define file argv[1]
     
    -#ifdef __MINGW32__
    +#ifdef _WIN32
         G_warning(_("Concurrent mapset locking is not supported on Windows"));
         exit(0);
     #else
    @@ -71,7 +71,7 @@ int find_process(int pid)
            kill failed because no such process, or because user is
            not owner of process
          */
    -#ifdef __MINGW32__
    +#ifdef _WIN32
         return 0;
     #else
         if (kill(pid, 0) == 0)
    diff --git a/lib/init/run.c b/lib/init/run.c
    index 4c048efdcec..6dae2af309e 100644
    --- a/lib/init/run.c
    +++ b/lib/init/run.c
    @@ -22,7 +22,7 @@ the user's shell to re-activate interrupts in shell-ese.
     int main(int argc, char *argv[])
     {
         signal(SIGINT, SIG_DFL);
    -#ifndef __MINGW32__
    +#ifndef _WIN32
         signal(SIGQUIT, SIG_DFL);
     #endif
     
    diff --git a/lib/iostream/rtimer.cpp b/lib/iostream/rtimer.cpp
    index 83ed7e44879..c0d8a4fd9fc 100644
    --- a/lib/iostream/rtimer.cpp
    +++ b/lib/iostream/rtimer.cpp
    @@ -33,10 +33,16 @@
      *  General Public License for more details.  *
      *  **************************************************************************/
     
    +#if !defined(_MSC_VER)
     #include 
    +#endif
    +
     #include 
     #include 
    +
    +#if !defined(_MSC_VER)
     #include 
    +#endif
     
     #include 
     
    diff --git a/lib/manage/sighold.c b/lib/manage/sighold.c
    index 7961f62f3dc..8fdbea604c4 100644
    --- a/lib/manage/sighold.c
    +++ b/lib/manage/sighold.c
    @@ -27,7 +27,7 @@ int M__hold_signals(int hold)
     
         signal(SIGINT, sig);
     
    -#ifndef __MINGW32__
    +#ifndef _WIN32
         signal(SIGQUIT, sig);
     #endif
     
    diff --git a/lib/pngdriver/graph_close.c b/lib/pngdriver/graph_close.c
    index 3496bdf1fa1..e6dba3f6166 100644
    --- a/lib/pngdriver/graph_close.c
    +++ b/lib/pngdriver/graph_close.c
    @@ -16,7 +16,7 @@
     #include 
     #include 
     #include 
    -#ifdef __MINGW32__
    +#ifdef _WIN32
     #include 
     #else
     #include 
    @@ -33,7 +33,7 @@ static void unmap_file(void)
         if (!png.mapped)
             return;
     
    -#ifdef __MINGW32__
    +#ifdef _WIN32
         UnmapViewOfFile(ptr);
         CloseHandle(png.handle);
     #else
    diff --git a/lib/pngdriver/graph_set.c b/lib/pngdriver/graph_set.c
    index 1fcf02bac8a..03c65ebbb8d 100644
    --- a/lib/pngdriver/graph_set.c
    +++ b/lib/pngdriver/graph_set.c
    @@ -18,7 +18,7 @@
     #include 
     #include 
     #include 
    -#ifdef __MINGW32__
    +#ifdef _WIN32
     #include 
     #else
     #include 
    @@ -41,7 +41,7 @@ static void map_file(void)
         if (fd < 0)
             return;
     
    -#ifdef __MINGW32__
    +#ifdef _WIN32
         png.handle = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL,
                                        PAGE_READWRITE, 0, size, NULL);
         if (!png.handle)
    diff --git a/lib/pngdriver/pngdriver.h b/lib/pngdriver/pngdriver.h
    index 62b61aa700e..24e7eb5c760 100644
    --- a/lib/pngdriver/pngdriver.h
    +++ b/lib/pngdriver/pngdriver.h
    @@ -16,7 +16,7 @@
     
     #include 
     
    -#ifdef __MINGW32__
    +#ifdef _WIN32
     #include 
     #endif
     
    @@ -34,7 +34,7 @@ struct png_state {
         int true_color;
         int has_alpha;
         int mapped;
    -#ifdef __MINGW32__
    +#ifdef _WIN32
         HANDLE handle;
     #endif
     
    @@ -54,13 +54,17 @@ extern void read_image(void);
     extern void read_ppm(void);
     extern void read_pgm(void);
     extern void read_bmp(void);
    +#ifdef HAVE_PNG_H
     extern void read_png(void);
    +#endif
     
     extern void write_image(void);
     extern void write_ppm(void);
     extern void write_pgm(void);
     extern void write_bmp(void);
    +#ifdef HAVE_PNG_H
     extern void write_png(void);
    +#endif
     
     extern void png_init_color_table(void);
     extern unsigned int png_get_color(int, int, int, int);
    diff --git a/lib/proj/CMakeLists.txt b/lib/proj/CMakeLists.txt
    new file mode 100644
    index 00000000000..bf80e1ddd6c
    --- /dev/null
    +++ b/lib/proj/CMakeLists.txt
    @@ -0,0 +1,21 @@
    +file(COPY desc.table DESTINATION etc/proj)
    +file(COPY parms.table DESTINATION etc/proj)
    +file(COPY units.table DESTINATION etc/proj)
    +
    +set(grass_gproj_SOURCES convert.c datum.c do_proj.c ellipse.c get_proj.c)
    +if(MINGW)
    +  list(APPEND grass_gproj_SOURCES "ftol.c")
    +endif()
    +
    +build_module(
    +  NAME
    +  grass_gproj
    +  DEPENDS
    +  grass_driver
    +  GDAL
    +  ZLIB
    +  PROJ
    +  SOURCES
    +  "${grass_gproj_SOURCES}"
    +  INCLUDES
    +  "../driver")
    diff --git a/lib/raster/close.c b/lib/raster/close.c
    index 7a0370285fc..a4ba0db5080 100644
    --- a/lib/raster/close.c
    +++ b/lib/raster/close.c
    @@ -12,7 +12,7 @@
      * \author USACERL and many others
      */
     
    -#ifdef __MINGW32__
    +#ifdef _WIN32
     #include 
     #endif
     
    @@ -51,7 +51,7 @@ static void sync_and_close(int fd, char *element, char *name)
          * after you are done writing all your data.
          */
     
    -#ifndef __MINGW32__
    +#ifndef _WIN32
         if (fsync(fd)) {
             G_warning(_("Unable to flush file %s for raster map %s: %s"), element,
                       name, strerror(errno));
    diff --git a/lib/raster/testsuite/test_raster_metadata.py b/lib/raster/testsuite/test_raster_metadata.py
    index 7da2c0fe4cf..43bbfaeea99 100644
    --- a/lib/raster/testsuite/test_raster_metadata.py
    +++ b/lib/raster/testsuite/test_raster_metadata.py
    @@ -8,6 +8,7 @@
     Read the file COPYING that comes with GRASS
     for details
     """
    +
     import random
     import string
     
    diff --git a/lib/raster3d/close.c b/lib/raster3d/close.c
    index 2622eb48d40..8af9ed1ac1a 100644
    --- a/lib/raster3d/close.c
    +++ b/lib/raster3d/close.c
    @@ -12,7 +12,7 @@
        \author USACERL and many others
      */
     
    -#ifdef __MINGW32__
    +#ifdef _WIN32
     #include 
     #endif
     #include 
    @@ -54,7 +54,7 @@ static int close_new(RASTER3D_Map *map)
     
         /* finally move tempfile to data file */
         Rast3d_filename(path, RASTER3D_CELL_ELEMENT, map->fileName, map->mapset);
    -#ifdef __MINGW32__
    +#ifdef _WIN32
         if (CopyFile(map->tempName, path, FALSE) == 0) {
     #else
         if (link(map->tempName, path) < 0) {
    diff --git a/lib/raster3d/test/test_raster3d_lib.h b/lib/raster3d/test/test_raster3d_lib.h
    index 4bcb53f5f59..5a1c57dd3ef 100644
    --- a/lib/raster3d/test/test_raster3d_lib.h
    +++ b/lib/raster3d/test/test_raster3d_lib.h
    @@ -20,8 +20,11 @@
     #include 
     #include 
     #include 
    +#ifdef HAVE_SYS_TIME_H
     #include 
    -
    +#else
    +#include 
    +#endif
     double compute_time_difference(struct timeval, struct timeval);
     int unit_test_coordinate_transform(void);
     int unit_test_put_get_value(void);
    diff --git a/lib/raster3d/test/test_tools.c b/lib/raster3d/test/test_tools.c
    index bb4ff23a7bd..97af63a7f7e 100644
    --- a/lib/raster3d/test/test_tools.c
    +++ b/lib/raster3d/test/test_tools.c
    @@ -19,6 +19,9 @@
     #include 
     #include 
     #include "test_raster3d_lib.h"
    +#ifdef _MSC_VER
    +#include 
    +#endif
     
     /* *************************************************************** */
     /* Compute the difference between two time steps ***************** */
    diff --git a/lib/raster3d/testsuite/raster3d_lib_test.py b/lib/raster3d/testsuite/raster3d_lib_test.py
    index 5ec919c94ba..a0020ab9ef1 100644
    --- a/lib/raster3d/testsuite/raster3d_lib_test.py
    +++ b/lib/raster3d/testsuite/raster3d_lib_test.py
    @@ -2,6 +2,7 @@
     
     @author Soeren Gebbert
     """
    +
     from grass.gunittest.case import TestCase
     
     
    diff --git a/lib/rst/CMakeLists.txt b/lib/rst/CMakeLists.txt
    new file mode 100644
    index 00000000000..a1f093f2ded
    --- /dev/null
    +++ b/lib/rst/CMakeLists.txt
    @@ -0,0 +1,35 @@
    +# add_subdirectory(data) add_subdirectory(qtree) add_subdirectory(interp_float)
    +
    +build_library_in_subdir(
    +  data
    +  NAME
    +  grass_interpdata
    +  DEPENDS
    +  grass_gis
    +  HEADERS
    +  "dataquad.h")
    +
    +build_library_in_subdir(
    +  qtree
    +  NAME
    +  grass_qtree
    +  DEPENDS
    +  grass_gis
    +  HEADERS
    +  "qtree.h")
    +
    +build_library_in_subdir(
    +  interp_float
    +  NAME
    +  grass_interpfl
    +  DEPENDS
    +  grass_gis
    +  grass_raster
    +  grass_bitmap
    +  grass_vector
    +  grass_qtree
    +  grass_interpdata
    +  OPTIONAL_DEPENDS
    +  OPENMP
    +  HEADERS
    +  "interpf.h")
    diff --git a/lib/temporal/CMakeLists.txt b/lib/temporal/CMakeLists.txt
    new file mode 100644
    index 00000000000..25617170411
    --- /dev/null
    +++ b/lib/temporal/CMakeLists.txt
    @@ -0,0 +1,6 @@
    +file(GLOB SQLFILES "SQL/*.sql")
    +foreach(sqlfile ${SQLFILES})
    +  install(FILES "${sqlfile}" DESTINATION etc/sql)
    +endforeach()
    +build_library_in_subdir(lib NAME grass_temporal DEPENDS grass_dbmibase
    +                        grass_datetime)
    diff --git a/lib/vector/CMakeLists.txt b/lib/vector/CMakeLists.txt
    new file mode 100644
    index 00000000000..4240de51851
    --- /dev/null
    +++ b/lib/vector/CMakeLists.txt
    @@ -0,0 +1,42 @@
    +# TODO: docs vectorascii PGM = vectorascii
    +
    +build_library_in_subdir(rtree HEADERS "rtree.h" DEPENDS grass_gis)
    +
    +add_subdirectory(dglib)
    +add_subdirectory(diglib)
    +
    +build_library_in_subdir(
    +  Vlib
    +  NAME
    +  grass_vector
    +  DEPENDS
    +  grass_gis
    +  grass_raster
    +  grass_rtree
    +  grass_graph
    +  grass_dig2
    +  grass_dbmibase
    +  grass_btree2
    +  grass_dbmiclient
    +  grass_linkm
    +  grass_gproj)
    +
    +if(TARGET POSTGRES)
    +  target_link_libraries(grass_vector POSTGRES)
    +endif()
    +
    +if(TARGET LAPACK)
    +  target_link_libraries(grass_vector LAPACK)
    +endif()
    +
    +build_library_in_subdir(vedit NAME grass_vedit DEPENDS grass_vector)
    +
    +build_library_in_subdir(
    +  neta
    +  NAME
    +  grass_neta
    +  DEPENDS
    +  grass_dbmiclient
    +  grass_gis
    +  grass_graph
    +  grass_vector)
    diff --git a/lib/vector/dglib/CMakeLists.txt b/lib/vector/dglib/CMakeLists.txt
    new file mode 100644
    index 00000000000..43fa06cbadb
    --- /dev/null
    +++ b/lib/vector/dglib/CMakeLists.txt
    @@ -0,0 +1,46 @@
    +# MODULE_TOPDIR = ../../..
    +
    +# include $(MODULE_TOPDIR)/include/Make/Vars.make
    +
    +# MOD_OBJS := $(filter-out %-template.o,$(AUTO_OBJS))
    +
    +# LIB = GRAPH
    +
    +# include $(MODULE_TOPDIR)/include/Make/Lib.make include
    +# $(MODULE_TOPDIR)/include/Make/Doxygen.make
    +
    +# DGLINC = $(ARCH_INCDIR)/dgl
    +
    +# default: headers $(MAKE) lib
    +
    +# headers: $(DGLINC)/avl.h $(DGLINC)/tavl.h $(DGLINC)/graph.h $(DGLINC)/heap.h \
    +# $(DGLINC)/tree.h $(DGLINC)/type.h $(DGLINC)/helpers.h $(DGLINC)/graph_v1.h
    +# $(DGLINC)/graph_v2.h \ $(ARCH_INCDIR)/dgl.h
    +
    +# $(DGLINC)/%.h: %.h | $(DGLINC) $(INSTALL_DATA) $< $@
    +
    +set(DGL_headers
    +    avl.h
    +    tavl.h
    +    graph.h
    +    heap.h
    +    tree.h
    +    type.h
    +    helpers.h
    +    graph_v1.h
    +    graph_v2.h)
    +foreach(DGL_header ${DGL_headers})
    +  file(COPY ${DGL_header} DESTINATION ${GISBASE}/include/grass/dgl)
    +endforeach()
    +
    +set(graphlib_SRCS
    +    avl.c
    +    graph.c
    +    graph_v2.c
    +    helpers.c
    +    tree.c
    +    graph_v1.c
    +    heap.c
    +    tavl.c)
    +
    +build_module(NAME grass_graph SOURCES "${graphlib_SRCS}" HEADERS "dgl.h")
    diff --git a/lib/vector/diglib/CMakeLists.txt b/lib/vector/diglib/CMakeLists.txt
    new file mode 100644
    index 00000000000..85fb9d45a25
    --- /dev/null
    +++ b/lib/vector/diglib/CMakeLists.txt
    @@ -0,0 +1,36 @@
    +set(dig2_SRCS
    +    allocation.c
    +    cindex.c
    +    frmt.c
    +    line_dist.c
    +    plus.c
    +    plus_node.c
    +    port_init.c
    +    prune.c
    +    struct_alloc.c
    +    update.c
    +    angle.c
    +    cindex_rw.c
    +    head.c
    +    linecros.c
    +    plus_area.c
    +    plus_struct.c
    +    spindex.c
    +    box.c
    +    file.c
    +    inside.c
    +    list.c
    +    plus_line.c
    +    poly.c
    +    portable.c
    +    spindex_rw.c
    +    type.c)
    +build_module(
    +  NAME
    +  grass_dig2
    +  SOURCES
    +  ${dig2_SRCS}
    +  DEPENDS
    +  grass_gmath
    +  grass_gis
    +  grass_rtree)
    diff --git a/lib/vector/diglib/plus_area.c b/lib/vector/diglib/plus_area.c
    index 8adf0952ab8..15c960231c6 100644
    --- a/lib/vector/diglib/plus_area.c
    +++ b/lib/vector/diglib/plus_area.c
    @@ -208,8 +208,10 @@ int dig_add_area(struct Plus_head *plus, int n_lines, plus_t *lines,
         if (Area == NULL)
             return -1;
     
    -    if (dig_area_alloc_line(Area, n_lines) == -1)
    +    if (dig_area_alloc_line(Area, n_lines) == -1) {
    +        dig_free_area(Area);
             return -1;
    +    }
     
         for (i = 0; i < n_lines; i++) {
             line = lines[i];
    @@ -220,6 +222,7 @@ int dig_add_area(struct Plus_head *plus, int n_lines, plus_t *lines,
                 if (topo->left != 0) {
                     G_warning(_("Line %d already has area/isle %d to left"), line,
                               topo->left);
    +                dig_free_area(Area);
                     return -1;
                 }
     
    @@ -230,6 +233,7 @@ int dig_add_area(struct Plus_head *plus, int n_lines, plus_t *lines,
                 if (topo->right != 0) {
                     G_warning(_("Line %d already has area/isle %d to right"), line,
                               topo->right);
    +                dig_free_area(Area);
                     return -1;
                 }
     
    @@ -719,8 +723,10 @@ int dig_add_isle(struct Plus_head *plus, int n_lines, plus_t *lines,
         if (Isle == NULL)
             return -1;
     
    -    if ((dig_isle_alloc_line(Isle, n_lines)) == -1)
    +    if ((dig_isle_alloc_line(Isle, n_lines)) == -1) {
    +        dig_free_isle(Isle);
             return -1;
    +    }
     
         Isle->area = 0;
     
    @@ -734,6 +740,7 @@ int dig_add_isle(struct Plus_head *plus, int n_lines, plus_t *lines,
                 if (topo->left != 0) {
                     G_warning(_("Line %d already has area/isle %d to left"), line,
                               topo->left);
    +                dig_free_isle(Isle);
                     return -1;
                 }
                 topo->left = -isle;
    @@ -742,6 +749,7 @@ int dig_add_isle(struct Plus_head *plus, int n_lines, plus_t *lines,
                 if (topo->right != 0) {
                     G_warning(_("Line %d already has area/isle %d to right"), line,
                               topo->right);
    +                dig_free_isle(Isle);
                     return -1;
                 }
     
    diff --git a/lib/vector/diglib/plus_struct.c b/lib/vector/diglib/plus_struct.c
    index c5a60f1e103..f0ab3d871c7 100644
    --- a/lib/vector/diglib/plus_struct.c
    +++ b/lib/vector/diglib/plus_struct.c
    @@ -68,30 +68,44 @@ int dig_Rd_P_node(struct Plus_head *Plus, int n, struct gvfile *fp)
         ptr = dig_alloc_node();
         ptr->n_lines = cnt;
     
    -    if (dig_node_alloc_line(ptr, ptr->n_lines) == -1)
    +    if (dig_node_alloc_line(ptr, ptr->n_lines) == -1) {
    +        dig_free_node(ptr);
             return -1;
    +    }
     
         if (ptr->n_lines) {
    -        if (0 >= dig__fread_port_P(ptr->lines, ptr->n_lines, fp))
    +        if (0 >= dig__fread_port_P(ptr->lines, ptr->n_lines, fp)) {
    +            dig_free_node(ptr);
                 return (-1);
    -        if (0 >= dig__fread_port_F(ptr->angles, ptr->n_lines, fp))
    +        }
    +        if (0 >= dig__fread_port_F(ptr->angles, ptr->n_lines, fp)) {
    +            dig_free_node(ptr);
                 return (-1);
    +        }
         }
     
    -    if (Plus->with_z)
    -        if (0 >= dig__fread_port_P(&n_edges, 1, fp)) /* reserved for edges */
    +    if (Plus->with_z) {
    +        if (0 >= dig__fread_port_P(&n_edges, 1, fp)) { /* reserved for edges */
    +            dig_free_node(ptr);
                 return (-1);
    -
    +        }
    +    }
         /* here will be edges */
     
    -    if (0 >= dig__fread_port_D(&(ptr->x), 1, fp))
    +    if (0 >= dig__fread_port_D(&(ptr->x), 1, fp)) {
    +        dig_free_node(ptr);
             return (-1);
    -    if (0 >= dig__fread_port_D(&(ptr->y), 1, fp))
    +    }
    +    if (0 >= dig__fread_port_D(&(ptr->y), 1, fp)) {
    +        dig_free_node(ptr);
             return (-1);
    +    }
     
         if (Plus->with_z) {
    -        if (0 >= dig__fread_port_D(&(ptr->z), 1, fp))
    +        if (0 >= dig__fread_port_D(&(ptr->z), 1, fp)) {
    +            dig_free_node(ptr);
                 return (-1);
    +        }
         }
         else
             ptr->z = 0;
    @@ -171,7 +185,7 @@ int dig_Rd_P_line(struct Plus_head *Plus, int n, struct gvfile *fp)
     
         /* offset */
         if (0 >= dig__fread_port_O(&(ptr->offset), 1, fp, Plus->off_t_size))
    -        return (-1);
    +        goto free_exit_failure;
     
         if (ptr->type == GV_POINT) {
             ptr->topo = NULL;
    @@ -185,29 +199,29 @@ int dig_Rd_P_line(struct Plus_head *Plus, int n, struct gvfile *fp)
             struct P_topo_c *topo = (struct P_topo_c *)ptr->topo;
     
             if (0 >= dig__fread_port_P(&(topo->area), 1, fp))
    -            return -1;
    +            goto free_exit_failure;
         }
         /* lines */
         else if (ptr->type & GV_LINE) {
             struct P_topo_l *topo = (struct P_topo_l *)ptr->topo;
     
             if (0 >= dig__fread_port_P(&(topo->N1), 1, fp))
    -            return -1;
    +            goto free_exit_failure;
             if (0 >= dig__fread_port_P(&(topo->N2), 1, fp))
    -            return -1;
    +            goto free_exit_failure;
         }
         /* boundaries */
         else if (ptr->type & GV_BOUNDARY) {
             struct P_topo_b *topo = (struct P_topo_b *)ptr->topo;
     
             if (0 >= dig__fread_port_P(&(topo->N1), 1, fp))
    -            return -1;
    +            goto free_exit_failure;
             if (0 >= dig__fread_port_P(&(topo->N2), 1, fp))
    -            return -1;
    +            goto free_exit_failure;
             if (0 >= dig__fread_port_P(&(topo->left), 1, fp))
    -            return -1;
    +            goto free_exit_failure;
             if (0 >= dig__fread_port_P(&(topo->right), 1, fp))
    -            return -1;
    +            goto free_exit_failure;
         }
         /* faces */
         else if ((ptr->type & GV_FACE) &&
    @@ -215,15 +229,15 @@ int dig_Rd_P_line(struct Plus_head *Plus, int n, struct gvfile *fp)
             struct P_topo_f *topo = (struct P_topo_f *)ptr->topo;
     
             if (0 >= dig__fread_port_I(&n_edges, 1, fp))
    -            return -1;
    +            goto free_exit_failure;
     
             /* here will be list of edges */
     
             /* left / right volume */
             if (0 >= dig__fread_port_P(&(topo->left), 1, fp))
    -            return -1;
    +            goto free_exit_failure;
             if (0 >= dig__fread_port_P(&(topo->left), 1, fp))
    -            return -1;
    +            goto free_exit_failure;
         }
         /* kernels */
         else if ((ptr->type & GV_KERNEL) &&
    @@ -231,12 +245,16 @@ int dig_Rd_P_line(struct Plus_head *Plus, int n, struct gvfile *fp)
             struct P_topo_k *topo = (struct P_topo_k *)ptr->topo;
     
             if (0 >= dig__fread_port_P(&(topo->volume), 1, fp))
    -            return -1;
    +            goto free_exit_failure;
         }
     
         Plus->Line[n] = ptr;
     
         return (0);
    +
    +free_exit_failure:
    +    dig_free_line(ptr);
    +    return -1;
     }
     
     int dig_Wr_P_line(struct Plus_head *Plus, int n, struct gvfile *fp)
    @@ -350,27 +368,40 @@ int dig_Rd_P_area(struct Plus_head *Plus, int n, struct gvfile *fp)
         /* boundaries */
         ptr->n_lines = cnt;
     
    -    if (dig_area_alloc_line(ptr, ptr->n_lines) == -1)
    +    if (dig_area_alloc_line(ptr, ptr->n_lines) == -1) {
    +        dig_free_area(ptr);
             return -1;
    +    }
     
    -    if (ptr->n_lines)
    -        if (0 >= dig__fread_port_P(ptr->lines, ptr->n_lines, fp))
    +    if (ptr->n_lines) {
    +        if (0 >= dig__fread_port_P(ptr->lines, ptr->n_lines, fp)) {
    +            dig_free_area(ptr);
                 return -1;
    +        }
    +    }
     
         /* isles */
    -    if (0 >= dig__fread_port_P(&(ptr->n_isles), 1, fp))
    +    if (0 >= dig__fread_port_P(&(ptr->n_isles), 1, fp)) {
    +        dig_free_area(ptr);
             return -1;
    +    }
     
    -    if (dig_area_alloc_isle(ptr, ptr->n_isles) == -1)
    +    if (dig_area_alloc_isle(ptr, ptr->n_isles) == -1) {
    +        dig_free_area(ptr);
             return -1;
    +    }
     
    -    if (ptr->n_isles)
    -        if (0 >= dig__fread_port_P(ptr->isles, ptr->n_isles, fp))
    +    if (ptr->n_isles) {
    +        if (0 >= dig__fread_port_P(ptr->isles, ptr->n_isles, fp)) {
    +            dig_free_area(ptr);
                 return -1;
    -
    +        }
    +    }
         /* centroid */
    -    if (0 >= dig__fread_port_P(&(ptr->centroid), 1, fp))
    +    if (0 >= dig__fread_port_P(&(ptr->centroid), 1, fp)) {
    +        dig_free_area(ptr);
             return -1;
    +    }
     
         Plus->Area[n] = ptr;
     
    @@ -435,16 +466,23 @@ int dig_Rd_P_isle(struct Plus_head *Plus, int n, struct gvfile *fp)
         /* boundaries */
         ptr->n_lines = cnt;
     
    -    if (dig_isle_alloc_line(ptr, ptr->n_lines) == -1)
    +    if (dig_isle_alloc_line(ptr, ptr->n_lines) == -1) {
    +        dig_free_isle(ptr);
             return -1;
    +    }
     
    -    if (ptr->n_lines)
    -        if (0 >= dig__fread_port_P(ptr->lines, ptr->n_lines, fp))
    +    if (ptr->n_lines) {
    +        if (0 >= dig__fread_port_P(ptr->lines, ptr->n_lines, fp)) {
    +            dig_free_isle(ptr);
                 return -1;
    +        }
    +    }
     
         /* area */
    -    if (0 >= dig__fread_port_P(&(ptr->area), 1, fp))
    +    if (0 >= dig__fread_port_P(&(ptr->area), 1, fp)) {
    +        dig_free_isle(ptr);
             return -1;
    +    }
     
         Plus->Isle[n] = ptr;
     
    diff --git a/lib/vector/diglib/spindex.c b/lib/vector/diglib/spindex.c
    index f56dd1f9adc..4f06630afff 100644
    --- a/lib/vector/diglib/spindex.c
    +++ b/lib/vector/diglib/spindex.c
    @@ -49,21 +49,25 @@ int dig_spidx_init(struct Plus_head *Plus)
             fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
             Plus->Node_spidx = RTreeCreateTree(fd, 0, ndims);
             remove(filename);
    +        G_free(filename);
     
             filename = G_tempfile();
             fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
             Plus->Line_spidx = RTreeCreateTree(fd, 0, ndims);
             remove(filename);
    +        G_free(filename);
     
             filename = G_tempfile();
             fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
             Plus->Area_spidx = RTreeCreateTree(fd, 0, ndims);
             remove(filename);
    +        G_free(filename);
     
             filename = G_tempfile();
             fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
             Plus->Isle_spidx = RTreeCreateTree(fd, 0, ndims);
             remove(filename);
    +        G_free(filename);
     
             Plus->Face_spidx = NULL;
             Plus->Volume_spidx = NULL;
    @@ -124,6 +128,7 @@ void dig_spidx_free_nodes(struct Plus_head *Plus)
             remove(filename);
             if (!Plus->Spidx_new)
                 close(Plus->Node_spidx->fd);
    +        G_free(filename);
         }
         else {
             RTreeDestroyTree(Plus->Node_spidx);
    @@ -156,6 +161,7 @@ void dig_spidx_free_lines(struct Plus_head *Plus)
             remove(filename);
             if (!Plus->Spidx_new)
                 close(Plus->Line_spidx->fd);
    +        G_free(filename);
         }
         else {
             RTreeDestroyTree(Plus->Line_spidx);
    @@ -188,6 +194,7 @@ void dig_spidx_free_areas(struct Plus_head *Plus)
             remove(filename);
             if (!Plus->Spidx_new)
                 close(Plus->Area_spidx->fd);
    +        G_free(filename);
         }
         else {
             RTreeDestroyTree(Plus->Area_spidx);
    @@ -220,6 +227,7 @@ void dig_spidx_free_isles(struct Plus_head *Plus)
             remove(filename);
             if (!Plus->Spidx_new)
                 close(Plus->Isle_spidx->fd);
    +        G_free(filename);
         }
         else {
             RTreeDestroyTree(Plus->Isle_spidx);
    diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt
    new file mode 100644
    index 00000000000..096432ea764
    --- /dev/null
    +++ b/man/CMakeLists.txt
    @@ -0,0 +1,6 @@
    +set(data_files
    +    grassdocs.css grass_logo.png grass_icon.png jquery.fixedheadertable.min.js
    +    parser_standard_options.js parser_standard_options.css)
    +
    +file(COPY ${data_files} DESTINATION docs/html)
    +install(FILES ${data_files} DESTINATION docs/html)
    diff --git a/man/build_rest.py b/man/build_rest.py
    index 37eaab80b94..ef684fd2de6 100644
    --- a/man/build_rest.py
    +++ b/man/build_rest.py
    @@ -170,7 +170,7 @@
     
     :doc:`Manual main page ` \| :doc:`Full Index `
      2003-2024 `GRASS Development Team `_, GRASS GIS ${grass_version} Reference Manual
    -"""
    +"""  # noqa: E501
     )
     
     cmd1_tmpl = string.Template(r"""*`$cmd.\* <${cmd}>` *""")
    diff --git a/man/parser_standard_options.py b/man/parser_standard_options.py
    index 3454084f330..6a6d769ab5e 100644
    --- a/man/parser_standard_options.py
    +++ b/man/parser_standard_options.py
    @@ -3,6 +3,7 @@
     
     @author: pietro
     """
    +
     import argparse
     import os
     import sys
    diff --git a/misc/CMakeLists.txt b/misc/CMakeLists.txt
    new file mode 100644
    index 00000000000..739c47f6ddf
    --- /dev/null
    +++ b/misc/CMakeLists.txt
    @@ -0,0 +1,12 @@
    +build_program_in_subdir(m.cogo DEPENDS grass_gis)
    +
    +build_program_in_subdir(m.measure DEPENDS grass_gis)
    +
    +build_program_in_subdir(m.transform DEPENDS grass_gis grass_imagery
    +                        grass_raster grass_vector)
    +
    +if(WITH_OPENGL)
    +  build_program_in_subdir(m.nviz.image DEPENDS grass_gis grass_ogsf grass_nviz)
    +
    +  build_program_in_subdir(m.nviz.script DEPENDS grass_gis grass_ogsf grass_nviz)
    +endif(WITH_OPENGL)
    diff --git a/misc/m.measure/main.c b/misc/m.measure/main.c
    index 8f7d3a4a3ef..45af6f14255 100644
    --- a/misc/m.measure/main.c
    +++ b/misc/m.measure/main.c
    @@ -53,7 +53,7 @@ int main(int argc, char **argv)
     
         units = G_define_standard_option(G_OPT_M_UNITS);
         units->label = _("Units");
    -    units->description = _("Default: location map units");
    +    units->description = _("Default: project map units");
     
         shell = G_define_flag();
         shell->key = 'g';
    diff --git a/msvc/strings.h b/msvc/strings.h
    new file mode 100644
    index 00000000000..dcf9ed87b7f
    --- /dev/null
    +++ b/msvc/strings.h
    @@ -0,0 +1,5 @@
    +/* MSVC does not have strings.h */
    +#ifndef _INC_STRINGS_H
    +#define _INC_STRINGS_H 1
    +#include 
    +#endif
    \ No newline at end of file
    diff --git a/msvc/unistd.h b/msvc/unistd.h
    new file mode 100644
    index 00000000000..a3370ffaa67
    --- /dev/null
    +++ b/msvc/unistd.h
    @@ -0,0 +1,59 @@
    +#ifndef _UNISTD_H
    +#define _UNISTD_H 1
    +
    +/* This file intended to serve as a drop-in replacement for
    + *  unistd.h on Windows.
    + *  Please add functionality as neeeded.
    + *  Original file from: http://stackoverflow.com/a/826027
    + */
    +
    +#include 
    +#include 
    +#include  /* for getpid() and the exec..() family */
    +#include   /* for _getcwd() and _chdir() */
    +
    +#define srandom srand
    +#define random  rand
    +
    +/* Values for the second argument to access.
    +   These may be OR'd together.  */
    +#define R_OK    4 /* Test for read permission.  */
    +#define W_OK    2 /* Test for write permission.  */
    +#define X_OK                                                            \
    +    R_OK                /* execute permission - unsupported in Windows, \
    +                           use R_OK instead. */
    +#define F_OK          0 /* Test for existence.  */
    +
    +#define access        _access
    +#define dup2          _dup2
    +#define execve        _execve
    +#define ftruncate     _chsize
    +#define unlink        _unlink
    +#define fileno        _fileno
    +#define getcwd        _getcwd
    +#define chdir         _chdir
    +#define isatty        _isatty
    +#define lseek         _lseek
    +/* read, write, and close are NOT being #defined here,
    + * because while there are file handle specific versions for Windows,
    + * they probably don't work for sockets.
    + * You need to look at your app and consider whether
    + * to call e.g. closesocket().
    + */
    +
    +// #define ssize_t int
    +
    +#define STDIN_FILENO  0
    +#define STDOUT_FILENO 1
    +#define STDERR_FILENO 2
    +/* should be in some equivalent to  */
    +
    +typedef __int16 int16_t;
    +typedef __int32 int32_t;
    +typedef __int64 int64_t;
    +typedef unsigned __int8 uint8_t;
    +typedef unsigned __int16 uint16_t;
    +typedef unsigned __int32 uint32_t;
    +typedef unsigned __int64 uint64_t;
    +
    +#endif /* unistd.h  */
    \ No newline at end of file
    diff --git a/mswindows/GRASS-Installer.nsi.tmpl b/mswindows/GRASS-Installer.nsi.tmpl
    index 47e7d6a025a..2b2722a5083 100644
    --- a/mswindows/GRASS-Installer.nsi.tmpl
    +++ b/mswindows/GRASS-Installer.nsi.tmpl
    @@ -557,7 +557,7 @@ Section "GRASS" SecGRASS
     	FileWrite $0 'set GISRC=dummy$\r$\n'
     	FileWrite $0 '$\r$\n'
     	FileWrite $0 'rem run g.mkfontcap outside a grass session$\r$\n'
    -	FileWrite $0 '"%GISBASE%\bin\g.mkfontcap.exe" -o$\r$\n'
    +	FileWrite $0 '"%GISBASE%\bin\g.mkfontcap.exe" --overwrite$\r$\n'
     	FileWrite $0 'exit$\r$\n'
     	FileClose $0
     	done_create_run_gmkfontcap.bat:
    diff --git a/mswindows/osgeo4w/postinstall.bat b/mswindows/osgeo4w/postinstall.bat
    index e9f75cecfdf..61d2d98b7d4 100644
    --- a/mswindows/osgeo4w/postinstall.bat
    +++ b/mswindows/osgeo4w/postinstall.bat
    @@ -24,6 +24,6 @@ rem GISRC must be set
     set GISRC=dummy
     
     rem run g.mkfontcap outside a GRASS session
    -"%GISBASE%\bin\g.mkfontcap.exe" -o
    +"%GISBASE%\bin\g.mkfontcap.exe" --overwrite
     
     del "%BATCH%.tmpl
    diff --git a/ps/CMakeLists.txt b/ps/CMakeLists.txt
    new file mode 100644
    index 00000000000..3c1ff397433
    --- /dev/null
    +++ b/ps/CMakeLists.txt
    @@ -0,0 +1,11 @@
    +build_program_in_subdir(
    +  ps.map
    +  DEPENDS
    +  grass_gis
    +  grass_raster
    +  grass_gmath
    +  grass_gproj
    +  grass_imagery
    +  grass_vector
    +  grass_dbmibase
    +  grass_sym)
    diff --git a/pyproject.toml b/pyproject.toml
    index e06ff451bd0..c99b85ab4dc 100644
    --- a/pyproject.toml
    +++ b/pyproject.toml
    @@ -1,24 +1,11 @@
     [tool.black]
    +required-version = '24'
     line-length = 88
    -target-version = ['py37', 'py38', 'py39', 'py310']
    -include = '\.pyi?$'
    -exclude = '''
    +target-version = ['py38', 'py39', 'py310', 'py311', 'py312']
    +# 'extend-exclude' excludes files or directories in addition to the defaults
    +extend-exclude = '''
     (
    -    # exclude directories in the root of the project
    -    /(
    -          \.eggs
    -        | \.git
    -        | \.hg
    -        | \.mypy_cache
    -        | \.tox
    -        | \.venv
    -        | _build
    -        | buck-out
    -        | build
    -        | bin\..*
    -        | dist\..*
    -    )/
    -    | python/libgrass_interface_generator/
    +    python/libgrass_interface_generator/
     )
     '''
     
    diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
    new file mode 100644
    index 00000000000..f3f28a0c1d0
    --- /dev/null
    +++ b/python/CMakeLists.txt
    @@ -0,0 +1,2 @@
    +add_subdirectory(grass)
    +add_subdirectory(libgrass_interface_generator)
    diff --git a/python/grass/CMakeLists.txt b/python/grass/CMakeLists.txt
    new file mode 100644
    index 00000000000..f7aad47ce65
    --- /dev/null
    +++ b/python/grass/CMakeLists.txt
    @@ -0,0 +1,61 @@
    +copy_python_files_in_subdir(exceptions etc/python/grass)
    +copy_python_files_in_subdir(gunittest etc/python/grass)
    +copy_python_files_in_subdir(grassdb etc/python/grass)
    +copy_python_files_in_subdir(imaging etc/python/grass)
    +copy_python_files_in_subdir(pydispatch etc/python/grass)
    +copy_python_files_in_subdir(script etc/python/grass)
    +copy_python_files_in_subdir(utils etc/python/grass)
    +copy_python_files_in_subdir(semantic_label etc/python/grass)
    +copy_python_files_in_subdir(temporal etc/python/grass)
    +copy_python_files_in_subdir(pygrass etc/python/grass)
    +copy_python_files_in_subdir(pygrass/messages etc/python/grass)
    +copy_python_files_in_subdir(pygrass/modules etc/python/grass)
    +copy_python_files_in_subdir(pygrass/raster etc/python/grass)
    +copy_python_files_in_subdir(pygrass/vector etc/python/grass)
    +copy_python_files_in_subdir(pygrass/gis etc/python/grass)
    +copy_python_files_in_subdir(pygrass/shell etc/python/grass)
    +copy_python_files_in_subdir(pygrass/tests etc/python/grass)
    +copy_python_files_in_subdir(pygrass/rpc etc/python/grass)
    +copy_python_files_in_subdir(pygrass/modules/interface etc/python/grass)
    +copy_python_files_in_subdir(pygrass/modules/grid etc/python/grass)
    +
    +configure_file(script/setup.py
    +               ${CMAKE_BINARY_DIR}/etc/python/grass/script/setup.py COPYONLY)
    +
    +add_custom_target(
    +  LIB_PYTHON
    +  COMMAND ${CMAKE_COMMAND} -E echo "#coding=utf-8" >
    +          ${GISBASE}/etc/python/__init__.py
    +  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py
    +          ${GISBASE}/etc/python/grass/
    +  COMMAND
    +    ${CMAKE_COMMAND} -E copy
    +    ${CMAKE_BINARY_DIR}/etc/python/grass/script/setup.py
    +    ${GISBASE}/etc/python/grass/script/
    +  VERBATIM
    +  DEPENDS python_exceptions
    +          python_grassdb
    +          python_imaging
    +          python_pydispatch
    +          python_script
    +          python_semantic_label
    +          python_temporal
    +          python_utils
    +          python_pygrass
    +          python_pygrass_messages
    +          python_pygrass_modules
    +          python_pygrass_modules
    +          python_pygrass_raster
    +          python_pygrass_vector
    +          python_pygrass_gis
    +          python_pygrass_shell
    +          python_pygrass_tests
    +          python_pygrass_rpc
    +          python_pygrass_modules_interface
    +          python_pygrass_modules_grid)
    +
    +# TODO: MODULES DISABLED add_subdirectory(ctypes)
    +
    +set_target_properties(LIB_PYTHON PROPERTIES FOLDER lib)
    +
    +install(DIRECTORY ${GISBASE}/etc/python/grass DESTINATION etc/python/grass/)
    diff --git a/python/grass/docs/conf.py b/python/grass/docs/conf.py
    index 991c54be8ef..2d6a564cac0 100644
    --- a/python/grass/docs/conf.py
    +++ b/python/grass/docs/conf.py
    @@ -73,13 +73,17 @@
         ),
     )
     
    -from grass.script import core
    +from grass.script import core  # noqa: E402
     
     footer_tmpl = string.Template(
         r"""
     {% block footer %}
    -

    Help Index | Topics Index | Keywords Index | Full Index

    -

    © 2003-${year} GRASS Development Team, GRASS GIS ${grass_version} Reference Manual

    +

    Help Index + | Topics Index + | Keywords Index + | Full Index

    +

    © 2003-${year} +GRASS Development Team, GRASS GIS ${grass_version} Reference Manual

    {% endblock %} """ ) diff --git a/python/grass/grassdb/create.py b/python/grass/grassdb/create.py index f7e7b509405..041b5ed28f8 100644 --- a/python/grass/grassdb/create.py +++ b/python/grass/grassdb/create.py @@ -9,7 +9,6 @@ .. sectionauthor:: Vaclav Petras """ - import os import shutil import getpass diff --git a/python/grass/grassdb/history.py b/python/grass/grassdb/history.py index 706edab2b7e..b1ddb52c19a 100644 --- a/python/grass/grassdb/history.py +++ b/python/grass/grassdb/history.py @@ -134,6 +134,25 @@ def read(history_path): return _read_from_plain_text(history_path) +def filter(json_data, command, timestamp): + """ + Filter JSON history file based on provided command and the time of command launch. + + :param json_data: List of dictionaries representing JSON entries + :param command: First filtering argument representing command as string + :param timestamp: Second filtering argument representing the time of command launch + :return: Index of entry matching the filter criteria. + """ + for index, entry in enumerate(json_data): + if entry["command_info"]: + if ( + entry["command"] == command + and entry["command_info"]["timestamp"] == timestamp + ): + return index + return None + + def _remove_entry_from_plain_text(history_path, index): """Remove entry from plain text history file. diff --git a/python/grass/grassdb/manage.py b/python/grass/grassdb/manage.py index c79df87ce07..0446263615e 100644 --- a/python/grass/grassdb/manage.py +++ b/python/grass/grassdb/manage.py @@ -9,7 +9,6 @@ .. sectionauthor:: Vaclav Petras """ - import os import shutil import sys diff --git a/python/grass/gunittest/case.py b/python/grass/gunittest/case.py index a6c89cbcaa8..3f67f729d14 100644 --- a/python/grass/gunittest/case.py +++ b/python/grass/gunittest/case.py @@ -1270,11 +1270,14 @@ def assertVectorAsciiEqualsVectorAscii( # a difference (always a iterator object is returned) if i > 0: # do HTML diff only if there is not too many lines - # TODO: this might be tough to do with some more sophisticated way of reports + # TODO: this might be tough to do with some more sophisticated way of + # reports if self.html_reports and i < maxlines: - # TODO: this might be here and somehow stored as file or done in reporter again if right information is stored + # TODO: this might be here and somehow stored as file or done in + # reporter again if right information is stored # i.e., files not deleted or the whole strings passed - # alternative is make_table() which is the same but creates just a table not a whole document + # alternative is make_table() which is the same but creates just a table + # not a whole document # TODO: all HTML files might be collected by the main reporter # TODO: standardize the format of name of HTML file # for one test id there is only one possible file of this name @@ -1357,7 +1360,8 @@ def runModule(cls, module, expecting_stdout=False, **kwargs): # should be done by some other function # TODO: this should be the function used for valgrind or profiling or debug # TODO: it asserts the rc but it does much more, so testModule? - # TODO: do we need special function for testing module failures or just add parameter returncode=0? + # TODO: do we need special function for testing module failures or just add + # parameter returncode=0? # TODO: consider not allowing to call this method more than once # the original idea was to run this method just once for test method # but for "integration" tests (script-like tests with more than one module) diff --git a/python/grass/gunittest/checkers.py b/python/grass/gunittest/checkers.py index 669bb03d9ed..cc0cdc0020d 100644 --- a/python/grass/gunittest/checkers.py +++ b/python/grass/gunittest/checkers.py @@ -23,7 +23,8 @@ # TODO: we are silent about the error and use a object with different # interface, should be replaced by central keyvalue module # this can happen when translations are not available - # TODO: grass should survive are give better error when tranlsations are not available + # TODO: grass should survive and give better errors when translations are not + # available # even the lazy loading after first _ call would be interesting # File "...grass/script/core.py", line 40, in # AttributeError: 'NoneType' object has no attribute 'endswith' @@ -41,7 +42,7 @@ def unify_projection(dic): Example of common typo in UTM replaced by correct spelling:: - >>> unify_projection({'name': ['Universe Transverse Mercator']}) + >>> unify_projection({"name": ["Universe Transverse Mercator"]}) {'name': ['Universal Transverse Mercator']} :param dic: The dictionary containing information about projection @@ -67,7 +68,7 @@ def unify_units(dic): Example of British English spelling replaced by US English spelling:: - >>> unify_units({'units': ['metres'], 'unit': ['metre']}) # doctest: +SKIP + >>> unify_units({"units": ["metres"], "unit": ["metre"]}) # doctest: +SKIP {'units': ['meters'], 'unit': ['meter']} :param dic: The dictionary containing information about units @@ -111,13 +112,13 @@ def value_from_string(value): Type conversions are applied in order ``int``, ``float``, ``string`` where string is no conversion. - >>> value_from_string('1') + >>> value_from_string("1") 1 - >>> value_from_string('5.6') + >>> value_from_string("5.6") 5.6 - >>> value_from_string(' 5.6\t ') + >>> value_from_string(" 5.6\t ") 5.6 - >>> value_from_string('hello') + >>> value_from_string("hello") 'hello' """ not_float = False @@ -178,10 +179,14 @@ def text_to_keyvalue( And example of converting text with text, floats, integers and list to a dictionary:: - >>> sorted(text_to_keyvalue('''a: Hello + >>> sorted( + ... text_to_keyvalue( + ... '''a: Hello ... b: 1.0 ... c: 1,2,3,4,5 - ... d : hello,8,0.1''').items()) # sorted items from the dictionary + ... d : hello,8,0.1''' + ... ).items() + ... ) # sorted items from the dictionary [('a', 'Hello'), ('b', 1.0), ('c', [1, 2, 3, 4, 5]), ('d', ['hello', 8, 0.1])] .. warning:: @@ -260,7 +265,7 @@ def values_equal(value_a, value_b, precision=0.000001): True >>> values_equal(1, 5.9, precision=10) True - >>> values_equal('Hello', 'hello') + >>> values_equal("Hello", "hello") False """ # each if body needs to handle only not equal state @@ -325,14 +330,21 @@ def keyvalue_equals( An example of key-value texts comparison:: - >>> keyvalue_equals(text_to_keyvalue('''a: Hello + >>> keyvalue_equals( + ... text_to_keyvalue( + ... '''a: Hello ... b: 1.0 ... c: 1,2,3,4,5 - ... d: hello,8,0.1'''), - ... text_to_keyvalue('''a: Hello + ... d: hello,8,0.1''' + ... ), + ... text_to_keyvalue( + ... '''a: Hello ... b: 1.1 ... c: 1,22,3,4,5 - ... d: hello,8,0.1'''), precision=0.1) + ... d: hello,8,0.1''' + ... ), + ... precision=0.1, + ... ) False :param dict_a: first dictionary @@ -381,8 +393,8 @@ def diff_keyvalue( The function returns missing keys and different values for common keys:: - >>> a = {'c': 2, 'b': 3, 'a': 4} - >>> b = {'c': 1, 'b': 3, 'd': 5} + >>> a = {"c": 2, "b": 3, "a": 4} + >>> b = {"c": 1, "b": 3, "d": 5} >>> diff_keyvalue(a, b, precision=0) (['d'], ['a'], [('c', 2, 1)]) @@ -486,32 +498,31 @@ def lowercase_equals(string_a, string_b, precision=None): # TODO: the behavior with last \n is strange but now using DOTALL and $ def check_text_ellipsis(reference, actual): r""" - >>> check_text_ellipsis("Vector map <...> contains ... points.", - ... "Vector map contains 5268 points.") + >>> check_text_ellipsis( + ... "Vector map <...> contains ... points.", + ... "Vector map contains 5268 points.", + ... ) True - >>> check_text_ellipsis("user: ...\\nname: elevation", - ... "user: some_user\\nname: elevation") + >>> check_text_ellipsis( + ... "user: ...\\nname: elevation", "user: some_user\\nname: elevation" + ... ) True - >>> check_text_ellipsis("user: ...\\nname: elevation", - ... "user: \\nname: elevation") + >>> check_text_ellipsis("user: ...\\nname: elevation", "user: \\nname: elevation") False The ellipsis is always considered even if it is followed by another dots. Consequently, a dot at the end of the sentence with preceding ellipsis will work as well as a line filled with undefined number of dots. - >>> check_text_ellipsis("The result is ....", - ... "The result is 25.") + >>> check_text_ellipsis("The result is ....", "The result is 25.") True - >>> check_text_ellipsis("max ..... ...", - ... "max ....... 6") + >>> check_text_ellipsis("max ..... ...", "max ....... 6") True However, there is no way how to express that the dot should be in the beginning and the ellipsis is at the end of the group of dots. - >>> check_text_ellipsis("The result is ....", - ... "The result is .25") + >>> check_text_ellipsis("The result is ....", "The result is .25") False The matching goes over lines (TODO: should this be changed?): @@ -521,8 +532,7 @@ def check_text_ellipsis(reference, actual): This function is based on regular expression containing .+ but no other regular expression matching will be done. - >>> check_text_ellipsis("Result: [569] (...)", - ... "Result: 9 (too high)") + >>> check_text_ellipsis("Result: [569] (...)", "Result: 9 (too high)") False """ ref_escaped = re.escape(reference) @@ -536,43 +546,55 @@ def check_text_ellipsis(reference, actual): def check_text_ellipsis_doctest(reference, actual): """ - >>> check_text_ellipsis_doctest("user: ...\\nname: elevation", - ... "user: some_user\\nname: elevation") + >>> check_text_ellipsis_doctest( + ... "user: ...\\nname: elevation", "user: some_user\\nname: elevation" + ... ) True - >>> check_text_ellipsis_doctest("user: ...\\nname: elevation", - ... "user: \\nname: elevation") + >>> check_text_ellipsis_doctest( + ... "user: ...\\nname: elevation", "user: \\nname: elevation" + ... ) True This function is using doctest's function to check the result, so we will discuss here how the underlying function behaves. >>> checker = doctest.OutputChecker() - >>> checker.check_output("user: some_user\\nname: elevation", - ... "user: some_user\\nname: elevation", - ... optionflags=None) + >>> checker.check_output( + ... "user: some_user\\nname: elevation", + ... "user: some_user\\nname: elevation", + ... optionflags=None, + ... ) True - >>> checker.check_output("user: user1\\nname: elevation", - ... "user: some_user\\nname: elevation", - ... optionflags=doctest.ELLIPSIS) + >>> checker.check_output( + ... "user: user1\\nname: elevation", + ... "user: some_user\\nname: elevation", + ... optionflags=doctest.ELLIPSIS, + ... ) False - >>> checker.check_output("user: ...\\nname: elevation", - ... "user: some_user\\nname: elevation", - ... optionflags=doctest.ELLIPSIS) + >>> checker.check_output( + ... "user: ...\\nname: elevation", + ... "user: some_user\\nname: elevation", + ... optionflags=doctest.ELLIPSIS, + ... ) True The ellipsis matches also an empty string, so the following matches: - >>> checker.check_output("user: ...\\nname: elevation", - ... "user: \\nname: elevation", - ... optionflags=doctest.ELLIPSIS) + >>> checker.check_output( + ... "user: ...\\nname: elevation", + ... "user: \\nname: elevation", + ... optionflags=doctest.ELLIPSIS, + ... ) True It is robust concerning misspelled matching string but does not allow ellipsis followed by a dot, e.g. at the end of the sentence: - >>> checker.check_output("user: ....\\nname: elevation", - ... "user: some_user\\nname: elevation", - ... optionflags=doctest.ELLIPSIS) + >>> checker.check_output( + ... "user: ....\\nname: elevation", + ... "user: some_user\\nname: elevation", + ... optionflags=doctest.ELLIPSIS, + ... ) False """ # this can be also global diff --git a/python/grass/gunittest/gmodules.py b/python/grass/gunittest/gmodules.py index c105fcfa12d..20d8bd2daed 100644 --- a/python/grass/gunittest/gmodules.py +++ b/python/grass/gunittest/gmodules.py @@ -22,15 +22,13 @@ class SimpleModule(Module): r"""Simple wrapper around pygrass.modules.Module to make sure that run\_, finish\_, stdout and stderr are set correctly. - >>> mapcalc = SimpleModule('r.mapcalc', expression='test_a = 1', - ... overwrite=True) + >>> mapcalc = SimpleModule("r.mapcalc", expression="test_a = 1", overwrite=True) >>> mapcalc.run() Module('r.mapcalc') >>> mapcalc.returncode 0 - >>> colors = SimpleModule('r.colors', - ... map='test_a', rules='-', stdin_='1 red') + >>> colors = SimpleModule("r.colors", map="test_a", rules="-", stdin_="1 red") >>> colors.run() Module('r.colors') >>> colors.returncode @@ -67,15 +65,17 @@ def call_module( ): r"""Run module with parameters given in `kwargs` and return its output. - >>> print (call_module('g.region', flags='pg')) # doctest: +ELLIPSIS + >>> print(call_module("g.region", flags="pg")) # doctest: +ELLIPSIS projection=... zone=... n=... s=... w=... - >>> call_module('m.proj', flags='i', input='-', stdin="50.0 41.5") + >>> call_module("m.proj", flags="i", input="-", stdin="50.0 41.5") '8642890.65|6965155.61|0.00\n' - >>> call_module('g.region', aabbbccc='notexist') # doctest: +IGNORE_EXCEPTION_DETAIL + >>> call_module( + ... "g.region", aabbbccc="notexist" + ... ) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... CalledModuleError: Module run g.region ... ended with error @@ -103,7 +103,7 @@ def call_module( .. note:: The data read is buffered in memory, so do not use this method if the data size is large or unlimited. - """ + """ # noqa: E501 # TODO: remove this: do_doctest_gettext_workaround() # implementation inspired by subprocess.check_output() function diff --git a/python/grass/gunittest/invoker.py b/python/grass/gunittest/invoker.py index c57df91960a..681fad5ff14 100644 --- a/python/grass/gunittest/invoker.py +++ b/python/grass/gunittest/invoker.py @@ -127,7 +127,8 @@ def _create_mapset(self, gisdbase, location, module): os.mkdir(mapset_dir) # TODO: default region in mapset will be what? # copy DEFAULT_WIND file from PERMANENT to WIND - # TODO: this should be a function in grass.script (used also in gis_set.py, PyGRASS also has its way with Mapset) + # TODO: this should be a function in grass.script (used also in gis_set.py, + # PyGRASS also has its way with Mapset) shutil.copy( os.path.join(gisdbase, location, "PERMANENT", "DEFAULT_WIND"), os.path.join(mapset_dir, "WIND"), @@ -212,7 +213,10 @@ def _run_test_module(self, module, results_dir, gisdbase, location, timeout): if stdout is None: stdout = "" if stderr is None: - stderr = f"Process has timed out in {timeout}s and produced no error output.\n" + stderr = ( + f"Process has timed out in {timeout}s and produced no error " + "output.\n" + ) # Return code is None if the process times out. # Rest of the code expects success to evaluate as False. # So, we assign a failing return code. diff --git a/python/grass/gunittest/main.py b/python/grass/gunittest/main.py index 18b2dfab5d1..631d0ee3116 100644 --- a/python/grass/gunittest/main.py +++ b/python/grass/gunittest/main.py @@ -82,7 +82,8 @@ def test(): """Run a test of a module.""" # TODO: put the link to to the report only if available # TODO: how to disable Python code coverage for module and C tests? - # TODO: we probably need to have different test functions for C, Python modules, and Python code + # TODO: we probably need to have different test functions for C, Python modules, + # and Python code # TODO: combine the results using python -m coverage --help | grep combine # TODO: function to anonymize/beautify file names (in content and actual filenames) # TODO: implement coverage but only when requested by invoker and only if diff --git a/python/grass/gunittest/multireport.py b/python/grass/gunittest/multireport.py index 54c1c915909..014d8296e4b 100644 --- a/python/grass/gunittest/multireport.py +++ b/python/grass/gunittest/multireport.py @@ -9,7 +9,6 @@ :authors: Vaclav Petras """ - import sys import os import argparse diff --git a/python/grass/gunittest/reporters.py b/python/grass/gunittest/reporters.py index 312a8fd6b89..252331840d2 100644 --- a/python/grass/gunittest/reporters.py +++ b/python/grass/gunittest/reporters.py @@ -1234,7 +1234,8 @@ def report_for_dir(self, root, directory, test_files): return row def report_for_dirs(self, root, directories): - # TODO: this will need chanages according to potential changes in absolute/relative paths + # TODO: this will need changes according to potential changes in + # absolute/relative paths page_name = os.path.join(root, self.main_page_name) page = open(page_name, "w") diff --git a/python/grass/gunittest/runner.py b/python/grass/gunittest/runner.py index 8879527a24c..891e1b65a5a 100644 --- a/python/grass/gunittest/runner.py +++ b/python/grass/gunittest/runner.py @@ -12,7 +12,6 @@ a template. It is not expected that something will left. """ - import sys import time diff --git a/python/grass/gunittest/testsuite/test_assertions.py b/python/grass/gunittest/testsuite/test_assertions.py index fb14e50bbd8..bf0f946d37d 100644 --- a/python/grass/gunittest/testsuite/test_assertions.py +++ b/python/grass/gunittest/testsuite/test_assertions.py @@ -2,7 +2,6 @@ Tests assertion methods. """ - import os import grass.script.core as gcore diff --git a/python/grass/gunittest/testsuite/test_checkers.py b/python/grass/gunittest/testsuite/test_checkers.py index 8d6571a8aa4..d35ffcb19d8 100644 --- a/python/grass/gunittest/testsuite/test_checkers.py +++ b/python/grass/gunittest/testsuite/test_checkers.py @@ -11,7 +11,6 @@ @author Vaclav Petras """ - from grass.script.utils import parse_key_val, try_remove from grass.gunittest.case import TestCase diff --git a/python/grass/imaging/images2gif.py b/python/grass/imaging/images2gif.py index f67bbed2a16..95d72add09a 100644 --- a/python/grass/imaging/images2gif.py +++ b/python/grass/imaging/images2gif.py @@ -891,7 +891,8 @@ def alterneigh(self, alpha, rad, i, b, g, r): # """ Search for biased BGR values # Finds closest neuron (min dist) and updates self.freq # finds best neuron (min dist-self.bias) and returns position - # for frequently chosen neurons, self.freq[i] is high and self.bias[i] is negative + # for frequently chosen neurons, self.freq[i] is high and self.bias[i] + # is negative # self.bias[i] = self.GAMMA * ((1/self.NETSIZE)-self.freq[i])""" # # i, j = self.SPECIALS, self.NETSIZE diff --git a/python/grass/imaging/operations.py b/python/grass/imaging/operations.py index d1837a485b0..8c60c4c599e 100644 --- a/python/grass/imaging/operations.py +++ b/python/grass/imaging/operations.py @@ -53,7 +53,6 @@ .. sectionauthor:: Vaclav Petras """ - # import similar to what is in visvis try: import PIL diff --git a/python/grass/jupyter/tests/seriesmap_test.py b/python/grass/jupyter/tests/seriesmap_test.py index 79f3b20dbda..e19faf5f663 100644 --- a/python/grass/jupyter/tests/seriesmap_test.py +++ b/python/grass/jupyter/tests/seriesmap_test.py @@ -1,6 +1,5 @@ """Test SeriesMap functions""" - from pathlib import Path import pytest diff --git a/python/grass/jupyter/tests/timeseriesmap_test.py b/python/grass/jupyter/tests/timeseriesmap_test.py index ed7e5c6e156..d75ec8372e4 100644 --- a/python/grass/jupyter/tests/timeseriesmap_test.py +++ b/python/grass/jupyter/tests/timeseriesmap_test.py @@ -1,6 +1,5 @@ """Test TimeSeriesMap functions""" - from pathlib import Path import pytest diff --git a/python/grass/pydispatch/dispatcher.py b/python/grass/pydispatch/dispatcher.py index a34706f8cf7..0915629fdd9 100644 --- a/python/grass/pydispatch/dispatcher.py +++ b/python/grass/pydispatch/dispatcher.py @@ -25,6 +25,7 @@ deletion, (considerably speeds up the cleanup process vs. the original code.) """ + import weakref from grass.pydispatch import saferef, robustapply, errors diff --git a/python/grass/pydispatch/robust.py b/python/grass/pydispatch/robust.py index f65471037d7..9923d3afc90 100644 --- a/python/grass/pydispatch/robust.py +++ b/python/grass/pydispatch/robust.py @@ -1,4 +1,5 @@ """Module implementing error-catching version of send (sendRobust)""" + from grass.pydispatch.dispatcher import Any, Anonymous, liveReceivers, getAllReceivers from grass.pydispatch.robustapply import robustApply diff --git a/python/grass/pydispatch/robustapply.py b/python/grass/pydispatch/robustapply.py index ac4211bbddf..1c10bc917c6 100644 --- a/python/grass/pydispatch/robustapply.py +++ b/python/grass/pydispatch/robustapply.py @@ -5,6 +5,7 @@ and subset the given arguments to match only those which are acceptable. """ + import sys if sys.hexversion >= 0x3000000: diff --git a/python/grass/pydispatch/signal.py b/python/grass/pydispatch/signal.py index edb962853da..1e968e99dca 100644 --- a/python/grass/pydispatch/signal.py +++ b/python/grass/pydispatch/signal.py @@ -4,7 +4,6 @@ @author Vaclav Petras """ - from grass.pydispatch import dispatcher diff --git a/python/grass/pygrass/CMakeLists.txt b/python/grass/pygrass/CMakeLists.txt new file mode 100644 index 00000000000..da001607086 --- /dev/null +++ b/python/grass/pygrass/CMakeLists.txt @@ -0,0 +1,26 @@ +execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory + etc/python/grass/pygrass/) +copy_python_file(${CMAKE_CURRENT_SOURCE_DIR}/errors.py etc/python/grass/pygrass) +copy_python_file(${CMAKE_CURRENT_SOURCE_DIR}/utils.py etc/python/grass/pygrass) +copy_python_file(${CMAKE_CURRENT_SOURCE_DIR}/orderdict.py + etc/python/grass/pygrass) + +build_pymodule_in_subdir(messages etc/python/grass/pygrass) + +build_pymodule_in_subdir(modules etc/python/grass/pygrass) + +build_pymodule_in_subdir(modules/interface etc/python/grass/pygrass/modules) + +build_pymodule_in_subdir(modules/grid etc/python/grass/pygrass/modules) + +build_pymodule_in_subdir(raster etc/python/grass/pygrass) + +build_pymodule_in_subdir(vector etc/python/grass/pygrass) + +build_pymodule_in_subdir(gis etc/python/grass/pygrass) + +build_pymodule_in_subdir(shell etc/python/grass/pygrass) + +build_pymodule_in_subdir(tests etc/python/grass/pygrass) + +build_pymodule_in_subdir(rpc etc/python/grass/pygrass) diff --git a/python/grass/pygrass/gis/region.py b/python/grass/pygrass/gis/region.py index 02a273a6ac6..a4a1a1b5e03 100644 --- a/python/grass/pygrass/gis/region.py +++ b/python/grass/pygrass/gis/region.py @@ -3,6 +3,7 @@ @author: Pietro Zambelli """ + import ctypes import grass.lib.gis as libgis import grass.lib.raster as libraster @@ -345,7 +346,7 @@ def keys(self): """Return a list of valid keys. :: >>> reg = Region() - >>> reg.keys() # doctest: +ELLIPSIS + >>> reg.keys() # doctest: +ELLIPSIS ['proj', 'zone', ..., 'cols', 'cells'] .. @@ -458,7 +459,8 @@ def from_rast(self, raster_name): libraster.Rast_get_cellhd(raster_name, mapset, self.byref()) def set_raster_region(self): - """Set the computational region (window) for all raster maps in the current process. + """Set the computational region (window) for all raster maps in the current + process. Attention: All raster objects must be closed or the process will be terminated. diff --git a/python/grass/pygrass/messages/__init__.py b/python/grass/pygrass/messages/__init__.py index 60e8e43e31c..36356433381 100644 --- a/python/grass/pygrass/messages/__init__.py +++ b/python/grass/pygrass/messages/__init__.py @@ -13,6 +13,7 @@ @author Soeren Gebbert """ + import sys from multiprocessing import Process, Lock, Pipe diff --git a/python/grass/pygrass/modules/grid/patch.py b/python/grass/pygrass/modules/grid/patch.py index 3d7c5432e43..be555583591 100644 --- a/python/grass/pygrass/modules/grid/patch.py +++ b/python/grass/pygrass/modules/grid/patch.py @@ -3,6 +3,7 @@ @author: pietro """ + from grass.pygrass.gis.region import Region from grass.pygrass.raster import RasterRow from grass.pygrass.utils import coor2pixel diff --git a/python/grass/pygrass/modules/grid/split.py b/python/grass/pygrass/modules/grid/split.py index a32665f5fcc..ea20a216e8e 100644 --- a/python/grass/pygrass/modules/grid/split.py +++ b/python/grass/pygrass/modules/grid/split.py @@ -3,6 +3,7 @@ @author: pietro """ + from grass.pygrass.gis.region import Region from grass.pygrass.vector.basic import Bbox @@ -81,10 +82,14 @@ def split_region_in_overlapping_tiles(region=None, width=100, height=100, overla 1500 >>> reg.rows 1350 - >>> split_region_in_overlapping_tiles(region=reg, width=1000, height=700, overlap=0) # doctest: +NORMALIZE_WHITESPACE + >>> split_region_in_overlapping_tiles( + ... region=reg, width=1000, height=700, overlap=0 + ... ) # doctest: +NORMALIZE_WHITESPACE [[Bbox(1350.0, 650.0, 1000.0, 0.0), Bbox(1350.0, 650.0, 1500.0, 1000.0)], [Bbox(650.0, 0.0, 1000.0, 0.0), Bbox(650.0, 0.0, 1500.0, 1000.0)]] - >>> split_region_in_overlapping_tiles(region=reg, width=1000, height=700, overlap=10) # doctest: +NORMALIZE_WHITESPACE + >>> split_region_in_overlapping_tiles( + ... region=reg, width=1000, height=700, overlap=10 + ... ) # doctest: +NORMALIZE_WHITESPACE [[Bbox(1350.0, 640.0, 1010.0, 0.0), Bbox(1350.0, 640.0, 1500.0, 990.0)], [Bbox(660.0, 0.0, 1010.0, 0.0), Bbox(660.0, 0.0, 1500.0, 990.0)]] """ @@ -103,7 +108,8 @@ def split_region_in_overlapping_tiles(region=None, width=100, height=100, overla def split_region_tiles(region=None, width=100, height=100): - """Split a region into a list of tiles defined as (start_row, end_row, start_col, end_col). + """Split a region into a list of tiles defined as (start_row, end_row, start_col, + end_col). :param region: a Region object to split :type region: Region object diff --git a/python/grass/pygrass/modules/interface/__init__.py b/python/grass/pygrass/modules/interface/__init__.py index 37546d463dd..a05211e21c3 100644 --- a/python/grass/pygrass/modules/interface/__init__.py +++ b/python/grass/pygrass/modules/interface/__init__.py @@ -3,6 +3,7 @@ @author: pietro """ + from grass.pygrass.modules.interface import flag from grass.pygrass.modules.interface import parameter from grass.pygrass.modules.interface import module diff --git a/python/grass/pygrass/modules/interface/env.py b/python/grass/pygrass/modules/interface/env.py index 98e5208ef5b..4fbef04dae3 100644 --- a/python/grass/pygrass/modules/interface/env.py +++ b/python/grass/pygrass/modules/interface/env.py @@ -3,6 +3,7 @@ @author: pietro """ + import os import sys diff --git a/python/grass/pygrass/modules/interface/module.py b/python/grass/pygrass/modules/interface/module.py index 57b4c235302..9f0c911a4b1 100644 --- a/python/grass/pygrass/modules/interface/module.py +++ b/python/grass/pygrass/modules/interface/module.py @@ -20,8 +20,8 @@ def _get_bash(self, *args, **kargs): class ParallelModuleQueue: - """This class is designed to run an arbitrary number of pygrass Module or MultiModule - processes in parallel. + """This class is designed to run an arbitrary number of pygrass Module or + MultiModule processes in parallel. Objects of type grass.pygrass.modules.Module or grass.pygrass.modules.MultiModule can be put into the @@ -55,8 +55,9 @@ class ParallelModuleQueue: >>> for i in range(5): ... new_mapcalc = copy.deepcopy(mapcalc) ... mapcalc_list.append(new_mapcalc) - ... m = new_mapcalc(expression="test_pygrass_%i = %i"%(i, i)) + ... m = new_mapcalc(expression="test_pygrass_%i = %i" % (i, i)) ... queue.put(m) + ... >>> queue.wait() >>> mapcalc_list = queue.get_finished_modules() >>> queue.get_num_run_procs() @@ -65,6 +66,7 @@ class ParallelModuleQueue: 3 >>> for mapcalc in mapcalc_list: ... print(mapcalc.returncode) + ... 0 0 0 @@ -78,8 +80,9 @@ class ParallelModuleQueue: >>> for i in range(5): ... new_mapcalc = copy.deepcopy(mapcalc) ... mapcalc_list.append(new_mapcalc) - ... m = new_mapcalc(expression="test_pygrass_%i = %i"%(i, i)) + ... m = new_mapcalc(expression="test_pygrass_%i = %i" % (i, i)) ... queue.put(m) + ... >>> queue.wait() >>> mapcalc_list = queue.get_finished_modules() >>> queue.get_num_run_procs() @@ -88,6 +91,7 @@ class ParallelModuleQueue: 8 >>> for mapcalc in mapcalc_list: ... print(mapcalc.returncode) + ... 0 0 0 @@ -103,10 +107,13 @@ class ParallelModuleQueue: ... new_gregion = copy.deepcopy(gregion) ... proc_list.append(new_gregion) ... new_mapcalc = copy.deepcopy(mapcalc) - ... m = new_mapcalc(expression="test_pygrass_%i = %i"%(i, i)) + ... m = new_mapcalc(expression="test_pygrass_%i = %i" % (i, i)) ... proc_list.append(new_mapcalc) - ... mm = MultiModule(module_list=[new_gregion, new_mapcalc], sync=False, set_temp_region=True) + ... mm = MultiModule( + ... module_list=[new_gregion, new_mapcalc], sync=False, set_temp_region=True + ... ) ... queue.put(mm) + ... >>> queue.wait() >>> proc_list = queue.get_finished_modules() >>> queue.get_num_run_procs() @@ -115,6 +122,7 @@ class ParallelModuleQueue: 3 >>> for proc in proc_list: ... print(proc.returncode) + ... 0 0 0 @@ -158,6 +166,7 @@ class ParallelModuleQueue: 8 >>> for mapcalc in mapcalc_list: ... print(mapcalc.returncode) + ... 0 0 0 @@ -182,12 +191,14 @@ class ParallelModuleQueue: >>> new_mapcalc = copy.deepcopy(mapcalc) >>> mapcalc_list.append(new_mapcalc) >>> m = new_mapcalc(expression="test_pygrass_3 =3") - >>> queue.put(m) # Now it will wait until all procs finish and set the counter back to 0 + >>> queue.put( + ... m + ... ) # Now it will wait until all procs finish and set the counter back to 0 >>> queue.get_num_run_procs() 0 >>> new_mapcalc = copy.deepcopy(mapcalc) >>> mapcalc_list.append(new_mapcalc) - >>> m = new_mapcalc(expression="test_pygrass_%i = %i"%(i, i)) + >>> m = new_mapcalc(expression="test_pygrass_%i = %i" % (i, i)) >>> queue.put(m) >>> queue.get_num_run_procs() 1 @@ -199,12 +210,13 @@ class ParallelModuleQueue: 3 >>> for mapcalc in mapcalc_list: ... print(mapcalc.returncode) + ... 0 0 0 0 - """ + """ # noqa: E501 def __init__(self, nprocs=1): """Constructor @@ -245,7 +257,8 @@ def get(self, num): :param num: the number of the object in queue :type num: int - :returns: the Module object or list of Module objects or None if num is not in the queue + :returns: the Module object or list of Module objects or None if num is not in + the queue """ if num < self._num_procs: return self._list[num] @@ -358,15 +371,21 @@ class Module: >>> new_neighbors3.get_bash() 'r.neighbors input=mapA size=3 method=average weighting_function=none nprocs=1 memory=300 output=mapB' - >>> mapcalc = Module("r.mapcalc", expression="test_a = 1", - ... overwrite=True, run_=False) + >>> mapcalc = Module( + ... "r.mapcalc", expression="test_a = 1", overwrite=True, run_=False + ... ) >>> mapcalc.run() Module('r.mapcalc') >>> mapcalc.returncode 0 - >>> mapcalc = Module("r.mapcalc", expression="test_a = 1", - ... overwrite=True, run_=False, finish_=False) + >>> mapcalc = Module( + ... "r.mapcalc", + ... expression="test_a = 1", + ... overwrite=True, + ... run_=False, + ... finish_=False, + ... ) >>> mapcalc.run() Module('r.mapcalc') >>> p = mapcalc.wait() @@ -378,9 +397,15 @@ class Module: >>> p.returncode 0 - >>> colors = Module("r.colors", map="test_a", rules="-", - ... run_=False, stdout_=PIPE, - ... stderr_=PIPE, stdin_="1 red") + >>> colors = Module( + ... "r.colors", + ... map="test_a", + ... rules="-", + ... run_=False, + ... stdout_=PIPE, + ... stderr_=PIPE, + ... stdin_="1 red", + ... ) >>> colors.run() Module('r.colors') >>> p = mapcalc.wait() @@ -393,8 +418,9 @@ class Module: >>> colors.outputs["stderr"].value.strip() "Color table for raster map set to 'rules'" - >>> colors = Module("r.colors", map="test_a", rules="-", - ... run_=False, finish_=False, stdin_=PIPE) + >>> colors = Module( + ... "r.colors", map="test_a", rules="-", run_=False, finish_=False, stdin_=PIPE + ... ) >>> colors.inputs["stdin"].value = "1 red" >>> colors.run() Module('r.colors') @@ -403,9 +429,15 @@ class Module: >>> colors.returncode 0 - >>> colors = Module("r.colors", map="test_a", rules="-", - ... run_=False, finish_=False, - ... stdin_=PIPE, stderr_=PIPE) + >>> colors = Module( + ... "r.colors", + ... map="test_a", + ... rules="-", + ... run_=False, + ... finish_=False, + ... stdin_=PIPE, + ... stderr_=PIPE, + ... ) >>> colors.inputs["stdin"].value = "1 red" >>> colors.run() Module('r.colors') @@ -466,15 +498,15 @@ def f(*args): therefore if we call the function like: - >>> f('grass', 'gis', 'modules') # doctest: +SKIP + >>> f("grass", "gis", "modules") # doctest: +SKIP grass gis modules or we can define a new list: - >>> words = ['grass', 'gis', 'modules'] # doctest: +SKIP - >>> f(*words) # doctest: +SKIP + >>> words = ["grass", "gis", "modules"] # doctest: +SKIP + >>> f(*words) # doctest: +SKIP grass gis modules @@ -489,8 +521,8 @@ def f(*args, **kargs): now we can use the new function, with: - >>> f('grass', 'gis', 'modules', os = 'linux', language = 'python') - ... # doctest: +SKIP + >>> f("grass", "gis", "modules", os="linux", language="python") + ... # doctest: +SKIP grass gis modules @@ -500,8 +532,8 @@ def f(*args, **kargs): or, as before we can, define a dictionary and give the dictionary to the function, like: - >>> keywords = {'os' : 'linux', 'language' : 'python'} # doctest: +SKIP - >>> f(*words, **keywords) # doctest: +SKIP + >>> keywords = {"os": "linux", "language": "python"} # doctest: +SKIP + >>> f(*words, **keywords) # doctest: +SKIP grass gis modules @@ -510,7 +542,7 @@ def f(*args, **kargs): In the Module class we heavily use this language feature to pass arguments and keyword arguments to the grass module. - """ + """ # noqa: E501 def __init__(self, cmd, *args, **kargs): if isinstance(cmd, str): @@ -842,20 +874,22 @@ class MultiModule: Module can be run in serial synchronously or asynchronously. - Synchronously: When calling run() all modules will run in serial order - until they are finished, The run() method will return until all modules finished. - The modules objects can be accessed by calling get_modules() to check their return - values. - - Asynchronously: When calling run() all modules will run in serial order in a background process. - Method run() will return after starting the modules without waiting for them to finish. - The user must call the wait() method to wait for the modules to finish. - Asynchronously called module can be optionally run in a temporary region - environment, hence invokeing g.region will not alter the current - region or the region of other MultiModule runs. + until they are finished, The run() method will return until all + modules finished. The modules objects can be accessed by calling + get_modules() to check their return values. + - Asynchronously: When calling run() all modules will run in serial order in a + background process. Method run() will return after starting the + modules without waiting for them to finish. The user must call + the wait() method to wait for the modules to finish. + Asynchronously called module can be optionally run in a temporary + region environment, hence invoking g.region will not alter the + current region or the region of other MultiModule runs. Note: - Modules run in asynchronous mode can only be accessed via the wait() method. - The wait() method will return all finished module objects as list. + Modules run in asynchronous mode can only be accessed via the + wait() method. The wait() method will return all finished + module objects as list. Objects of this class can be passed to the ParallelModuleQueue to run serial stacks of modules in parallel. This is meaningful if region settings must be applied @@ -892,8 +926,9 @@ class MultiModule: >>> region_4.flags.p = True >>> region_5 = copy.deepcopy(region_1) >>> region_5.flags.p = True - >>> mm = MultiModule(module_list=[region_1, region_2, region_3, region_4, region_5], - ... sync=False) + >>> mm = MultiModule( + ... module_list=[region_1, region_2, region_3, region_4, region_5], sync=False + ... ) >>> t = mm.run() >>> isinstance(t, Process) True @@ -911,8 +946,11 @@ class MultiModule: Asynchronous module run, setting finish = False and using temporary region - >>> mm = MultiModule(module_list=[region_1, region_2, region_3, region_4, region_5], - ... sync=False, set_temp_region=True) + >>> mm = MultiModule( + ... module_list=[region_1, region_2, region_3, region_4, region_5], + ... sync=False, + ... set_temp_region=True, + ... ) >>> str(mm) 'g.region -p ; g.region -p ; g.region -p ; g.region -p ; g.region -p' >>> t = mm.run() @@ -936,12 +974,14 @@ def __init__(self, module_list, sync=True, set_temp_region=False): """Constructor of the multi module class :param module_list: A list of pre-configured Module objects that should be run - :param sync: If set True the run() method will wait for all processes to finish -> synchronously run. - If set False, the run() method will return after starting the processes -> asynchronously run. - The wait() method must be called to finish the modules. - :param set_temp_region: Set a temporary region in which the modules should be run, hence - region settings in the process list will not affect the current - computation region. + :param sync: If set True the run() method will wait for all processes to finish + -> synchronously run. + If set False, the run() method will return after starting the + processes -> asynchronously run. The wait() method must be called + to finish the modules. + :param set_temp_region: Set a temporary region in which the modules should be + run, hence region settings in the process list will not + affect the current computation region. Note: diff --git a/python/grass/pygrass/modules/interface/parameter.py b/python/grass/pygrass/modules/interface/parameter.py index 7ab67c186ad..4d769972e10 100644 --- a/python/grass/pygrass/modules/interface/parameter.py +++ b/python/grass/pygrass/modules/interface/parameter.py @@ -3,6 +3,7 @@ @author: pietro """ + import re from grass.pygrass.modules.interface.docstring import docstring_property @@ -114,8 +115,8 @@ def check_string(value): break if not good: raise ValueError( - f"The Parameter <{param.name}>, must be one of the following values:" - f" {param.values!r} not '{newvalue}'" + f"The Parameter <{param.name}>, must be one of the following " + f"values: {param.values!r} not '{newvalue}'" ) return ( ( @@ -134,9 +135,15 @@ class Parameter: """The Parameter object store all information about a parameter of a GRASS GIS module. :: - >>> param = Parameter(diz=dict(name='int_number', required='yes', - ... multiple='no', type='integer', - ... values=[2, 4, 6, 8])) + >>> param = Parameter( + ... diz=dict( + ... name="int_number", + ... required="yes", + ... multiple="no", + ... type="integer", + ... values=[2, 4, 6, 8], + ... ) + ... ) >>> param.value = 2 >>> param.value 2 @@ -146,7 +153,7 @@ class Parameter: ValueError: The Parameter , must be one of the following values: [2, 4, 6, 8] not '3' ... - """ + """ # noqa: E501 def __init__(self, xparameter=None, diz=None): self._value = None @@ -237,9 +244,16 @@ def rawvalue(self): def get_bash(self): """Return the BASH representation of the parameter. :: - >>> param = Parameter(diz=dict(name='int_number', required='yes', - ... multiple='no', type='integer', - ... values=[2, 4, 6, 8], default=8)) + >>> param = Parameter( + ... diz=dict( + ... name="int_number", + ... required="yes", + ... multiple="no", + ... type="integer", + ... values=[2, 4, 6, 8], + ... default=8, + ... ) + ... ) >>> param.get_bash() 'int_number=8' @@ -249,9 +263,11 @@ def get_bash(self): if isinstance(self.rawvalue, (list, tuple)): value = sep.join( [ - sep.join([str(v) for v in val]) - if isinstance(val, tuple) - else str(val) + ( + sep.join([str(v) for v in val]) + if isinstance(val, tuple) + else str(val) + ) for val in self.rawvalue ] ) @@ -262,9 +278,16 @@ def get_bash(self): def get_python(self): """Return a string with the Python representation of the parameter. :: - >>> param = Parameter(diz=dict(name='int_number', required='yes', - ... multiple='no', type='integer', - ... values=[2, 4, 6, 8], default=8)) + >>> param = Parameter( + ... diz=dict( + ... name="int_number", + ... required="yes", + ... multiple="no", + ... type="integer", + ... values=[2, 4, 6, 8], + ... default=8, + ... ) + ... ) >>> param.get_python() 'int_number=8' @@ -298,11 +321,17 @@ def __doc__(self): :: - >>> param = Parameter(diz=dict(name='int_number', - ... description="Set an number", - ... required='yes', - ... multiple='no', type='integer', - ... values=[2, 4, 6, 8], default=8)) + >>> param = Parameter( + ... diz=dict( + ... name="int_number", + ... description="Set an number", + ... required="yes", + ... multiple="no", + ... type="integer", + ... values=[2, 4, 6, 8], + ... default=8, + ... ) + ... ) >>> print(param.__doc__) int_number: 8, required, integer Set an number diff --git a/python/grass/pygrass/modules/interface/testsuite/test_flag.py b/python/grass/pygrass/modules/interface/testsuite/test_flag.py index 26b9ba531ff..909c6d00d55 100644 --- a/python/grass/pygrass/modules/interface/testsuite/test_flag.py +++ b/python/grass/pygrass/modules/interface/testsuite/test_flag.py @@ -3,6 +3,7 @@ @author: pietro """ + from grass.gunittest.case import TestCase from grass.gunittest.main import test diff --git a/python/grass/pygrass/modules/interface/testsuite/test_modules.py b/python/grass/pygrass/modules/interface/testsuite/test_modules.py index 10b4c3f2529..3318154f87d 100644 --- a/python/grass/pygrass/modules/interface/testsuite/test_modules.py +++ b/python/grass/pygrass/modules/interface/testsuite/test_modules.py @@ -3,6 +3,7 @@ @author: pietro """ + from fnmatch import fnmatch from io import BytesIO @@ -19,20 +20,6 @@ ] -# taken from six -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - class metaclass(meta): - def __new__(cls, name, this_bases, d): - return meta(name, bases, d) - - return type.__new__(metaclass, "temporary_class", (), {}) - - class ModulesMeta(type): def __new__(mcs, name, bases, dict): def gen_test(cmd): @@ -52,7 +39,7 @@ def test(self): return type.__new__(mcs, name, bases, dict) -class TestModules(with_metaclass(ModulesMeta, TestCase)): +class TestModules(TestCase, metaclass=ModulesMeta): pass diff --git a/python/grass/pygrass/modules/interface/testsuite/test_parameter.py b/python/grass/pygrass/modules/interface/testsuite/test_parameter.py index e3bf9921bfd..57f17cb3027 100644 --- a/python/grass/pygrass/modules/interface/testsuite/test_parameter.py +++ b/python/grass/pygrass/modules/interface/testsuite/test_parameter.py @@ -3,6 +3,7 @@ @author: pietro """ + from grass.gunittest.case import TestCase from grass.gunittest.main import test diff --git a/python/grass/pygrass/modules/interface/typedict.py b/python/grass/pygrass/modules/interface/typedict.py index f2ece769d6c..c8fdeb48a76 100644 --- a/python/grass/pygrass/modules/interface/typedict.py +++ b/python/grass/pygrass/modules/interface/typedict.py @@ -3,6 +3,7 @@ @author: pietro """ + from collections import OrderedDict from copy import deepcopy diff --git a/python/grass/pygrass/modules/testsuite/test_import_isolation.py b/python/grass/pygrass/modules/testsuite/test_import_isolation.py index d91ae1a830b..d1321a554d0 100644 --- a/python/grass/pygrass/modules/testsuite/test_import_isolation.py +++ b/python/grass/pygrass/modules/testsuite/test_import_isolation.py @@ -9,6 +9,7 @@ Created on Wed Jul 15 11:34:32 2015 """ + import sys import fnmatch diff --git a/python/grass/pygrass/raster/__init__.py b/python/grass/pygrass/raster/__init__.py index a151e1d35e3..448d4e3b1db 100644 --- a/python/grass/pygrass/raster/__init__.py +++ b/python/grass/pygrass/raster/__init__.py @@ -13,16 +13,12 @@ libgis.G_gisinit("") -# # import pygrass modules -# from grass.pygrass.errors import must_be_open from grass.pygrass.gis.region import Region from grass.pygrass import utils -# # import raster classes -# from grass.pygrass.raster.abstract import RasterAbstractBase from grass.pygrass.raster.raster_type import TYPE as RTYPE, RTYPE_STR from grass.pygrass.raster.buffer import Buffer diff --git a/python/grass/pygrass/raster/abstract.py b/python/grass/pygrass/raster/abstract.py index 76d638db7db..4967dc6487b 100644 --- a/python/grass/pygrass/raster/abstract.py +++ b/python/grass/pygrass/raster/abstract.py @@ -3,6 +3,7 @@ @author: pietro """ + import ctypes # @@ -48,7 +49,7 @@ def __init__(self, name, mapset=""): >>> info = Info(test_raster_name) >>> info.read() - >>> info # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE + >>> info # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE abstract_test_map@ rows: 4 cols: 4 @@ -538,7 +539,8 @@ def _set_raster_window(self, region): def get_value(self, point, region=None): """This method returns the pixel value of a given pair of coordinates: - :param point: pair of coordinates in tuple object or class object with coords() method + :param point: pair of coordinates in tuple object or class object with coords() + method """ # Check for tuple if not isinstance(point, list) and not isinstance(point, tuple): diff --git a/python/grass/pygrass/raster/category.py b/python/grass/pygrass/raster/category.py index b7a1294d96c..b43a10ae48d 100644 --- a/python/grass/pygrass/raster/category.py +++ b/python/grass/pygrass/raster/category.py @@ -3,6 +3,7 @@ @author: pietro """ + import ctypes from operator import itemgetter diff --git a/python/grass/pygrass/raster/history.py b/python/grass/pygrass/raster/history.py index 6140a6197b2..5041c9e55d8 100644 --- a/python/grass/pygrass/raster/history.py +++ b/python/grass/pygrass/raster/history.py @@ -3,6 +3,7 @@ @author: pietro """ + import ctypes import grass.lib.raster as libraster import datetime diff --git a/python/grass/pygrass/raster/raster_type.py b/python/grass/pygrass/raster/raster_type.py index 0b8244fe551..aa54a6d6df6 100644 --- a/python/grass/pygrass/raster/raster_type.py +++ b/python/grass/pygrass/raster/raster_type.py @@ -3,6 +3,7 @@ @author: pietro """ + import grass.lib.raster as libraster import ctypes import numpy as np diff --git a/python/grass/pygrass/raster/rowio.py b/python/grass/pygrass/raster/rowio.py index 650419122c3..62c5683ef68 100644 --- a/python/grass/pygrass/raster/rowio.py +++ b/python/grass/pygrass/raster/rowio.py @@ -3,6 +3,7 @@ @author: pietro """ + import ctypes import grass.lib.rowio as librowio diff --git a/python/grass/pygrass/raster/segment.py b/python/grass/pygrass/raster/segment.py index 6e9c4c4c781..60966d0f846 100644 --- a/python/grass/pygrass/raster/segment.py +++ b/python/grass/pygrass/raster/segment.py @@ -3,6 +3,7 @@ @author: pietro """ + import ctypes import grass.lib.gis as libgis import grass.lib.raster as libraster diff --git a/python/grass/pygrass/raster/testsuite/test_numpy.py b/python/grass/pygrass/raster/testsuite/test_numpy.py index c773e628f96..a2a6e1cdd26 100644 --- a/python/grass/pygrass/raster/testsuite/test_numpy.py +++ b/python/grass/pygrass/raster/testsuite/test_numpy.py @@ -3,6 +3,7 @@ @author: lucadelu """ + from grass.gunittest.case import TestCase from grass.gunittest.main import test from numpy.random import random diff --git a/python/grass/pygrass/rpc/__init__.py b/python/grass/pygrass/rpc/__init__.py index c5797c19caa..07cbfe6503a 100644 --- a/python/grass/pygrass/rpc/__init__.py +++ b/python/grass/pygrass/rpc/__init__.py @@ -273,30 +273,38 @@ def get_raster_image_as_np(self, name, mapset=None, extent=None, color="RGB"): >>> len(ret) 64 - >>> extent = {"north":30, "south":10, "east":30, "west":10, - ... "rows":2, "cols":2} - >>> ret = provider.get_raster_image_as_np(name=test_raster_name, - ... extent=extent) + >>> extent = { + ... "north": 30, + ... "south": 10, + ... "east": 30, + ... "west": 10, + ... "rows": 2, + ... "cols": 2, + ... } + >>> ret = provider.get_raster_image_as_np(name=test_raster_name, extent=extent) >>> len(ret) 16 - >>> extent = {"rows":3, "cols":1} - >>> ret = provider.get_raster_image_as_np(name=test_raster_name, - ... extent=extent) + >>> extent = {"rows": 3, "cols": 1} + >>> ret = provider.get_raster_image_as_np(name=test_raster_name, extent=extent) >>> len(ret) 12 - >>> extent = {"north":100, "south":10, "east":30, "west":10, - ... "rows":2, "cols":2} - >>> ret = provider.get_raster_image_as_np(name=test_raster_name, - ... extent=extent) + >>> extent = { + ... "north": 100, + ... "south": 10, + ... "east": 30, + ... "west": 10, + ... "rows": 2, + ... "cols": 2, + ... } + >>> ret = provider.get_raster_image_as_np(name=test_raster_name, extent=extent) >>> provider.stop() >>> time.sleep(1) - >>> extent = {"rows":3, "cols":1} - >>> ret = provider.get_raster_image_as_np(name=test_raster_name, - ... extent=extent) + >>> extent = {"rows": 3, "cols": 1} + >>> ret = provider.get_raster_image_as_np(name=test_raster_name, extent=extent) >>> len(ret) 12 @@ -325,18 +333,18 @@ def get_vector_table_as_dict(self, name, mapset=None, where=None): {1: [1, 'point', 1.0], 2: [2, 'line', 2.0], 3: [3, 'centroid', 3.0]} >>> ret["columns"] Columns([('cat', 'INTEGER'), ('name', 'varchar(50)'), ('value', 'double precision')]) - >>> ret = provider.get_vector_table_as_dict(name=test_vector_name, - ... where="value > 1") + >>> ret = provider.get_vector_table_as_dict( + ... name=test_vector_name, where="value > 1" + ... ) >>> ret["table"] {2: [2, 'line', 2.0], 3: [3, 'centroid', 3.0]} >>> ret["columns"] Columns([('cat', 'INTEGER'), ('name', 'varchar(50)'), ('value', 'double precision')]) - >>> provider.get_vector_table_as_dict(name="no_map", - ... where="value > 1") + >>> provider.get_vector_table_as_dict(name="no_map", where="value > 1") >>> provider.stop() .. - """ + """ # noqa: E501 self.check_server() self.client_conn.send([RPCDefs.GET_VECTOR_TABLE_AS_DICT, name, mapset, where]) return self.safe_receive("get_vector_table_as_dict") @@ -360,64 +368,70 @@ def get_vector_features_as_wkb_list( >>> from grass.pygrass.rpc import DataProvider >>> provider = DataProvider() - >>> wkb = provider.get_vector_features_as_wkb_list(name=test_vector_name, - ... extent=None, - ... feature_type="point") + >>> wkb = provider.get_vector_features_as_wkb_list( + ... name=test_vector_name, extent=None, feature_type="point" + ... ) >>> for entry in wkb: ... f_id, cat, string = entry ... print(f_id, cat, len(string)) + ... 1 1 21 2 1 21 3 1 21 - >>> extent = {"north":6.6, "south":5.5, "east":14.5, "west":13.5} - >>> wkb = provider.get_vector_features_as_wkb_list(name=test_vector_name, - ... extent=extent, - ... feature_type="point") + >>> extent = {"north": 6.6, "south": 5.5, "east": 14.5, "west": 13.5} + >>> wkb = provider.get_vector_features_as_wkb_list( + ... name=test_vector_name, extent=extent, feature_type="point" + ... ) >>> for entry in wkb: ... f_id, cat, string = entry ... print(f_id, cat, len(string)) + ... 3 1 21 - >>> wkb = provider.get_vector_features_as_wkb_list(name=test_vector_name, - ... extent=None, - ... feature_type="line") + >>> wkb = provider.get_vector_features_as_wkb_list( + ... name=test_vector_name, extent=None, feature_type="line" + ... ) >>> for entry in wkb: ... f_id, cat, string = entry ... print(f_id, cat, len(string)) + ... 4 2 57 5 2 57 6 2 57 - >>> wkb = provider.get_vector_features_as_wkb_list(name=test_vector_name, - ... extent=None, - ... feature_type="centroid") + >>> wkb = provider.get_vector_features_as_wkb_list( + ... name=test_vector_name, extent=None, feature_type="centroid" + ... ) >>> for entry in wkb: ... f_id, cat, string = entry ... print(f_id, cat, len(string)) + ... 19 3 21 18 3 21 20 3 21 21 3 21 - >>> wkb = provider.get_vector_features_as_wkb_list(name=test_vector_name, - ... extent=None, - ... feature_type="area") + >>> wkb = provider.get_vector_features_as_wkb_list( + ... name=test_vector_name, extent=None, feature_type="area" + ... ) >>> for entry in wkb: ... f_id, cat, string = entry ... print(f_id, cat, len(string)) + ... 1 3 225 2 3 141 3 3 93 4 3 141 - >>> wkb = provider.get_vector_features_as_wkb_list(name=test_vector_name, - ... extent=None, - ... feature_type="boundary") + >>> wkb = provider.get_vector_features_as_wkb_list( + ... name=test_vector_name, extent=None, feature_type="boundary" + ... ) >>> for entry in wkb: ... f_id, cat, string = entry ... print(f_id, cat, len(string)) + ... 10 None 41 7 None 41 8 None 41 diff --git a/python/grass/pygrass/shell/conversion.py b/python/grass/pygrass/shell/conversion.py index 344dfd2811b..76802c08ce1 100644 --- a/python/grass/pygrass/shell/conversion.py +++ b/python/grass/pygrass/shell/conversion.py @@ -4,7 +4,6 @@ @author: pietro """ - dcont = """ {key} {value} diff --git a/python/grass/pygrass/tests/benchmark.py b/python/grass/pygrass/tests/benchmark.py index 422feb0eec9..c63dcb8d02e 100644 --- a/python/grass/pygrass/tests/benchmark.py +++ b/python/grass/pygrass/tests/benchmark.py @@ -343,7 +343,7 @@ def print_test(testdict): TXT = """ {% for region in regions %} {{ '#'*60 }} -### Benchmark cols = {{ region.cols }} rows = {{ region.rows}} cells = {{ region.cells }} +# Benchmark cols = {{ region.cols }} rows = {{ region.rows }} cells = {{ region.cells }} {{ '#'*60 }} # equation: c = a + b diff --git a/python/grass/pygrass/utils.py b/python/grass/pygrass/utils.py index 96fe731ee3d..38a78277dd0 100644 --- a/python/grass/pygrass/utils.py +++ b/python/grass/pygrass/utils.py @@ -6,6 +6,7 @@ import grass.lib.gis as libgis libgis.G_gisinit("") + import grass.lib.raster as libraster from grass.lib.ctypes_preamble import String from grass.script import core as grasscore @@ -21,7 +22,7 @@ def looking(obj, filter_string): """ >>> import grass.lib.vector as libvect - >>> sorted(looking(libvect, '*by_box*')) # doctest: +NORMALIZE_WHITESPACE + >>> sorted(looking(libvect, "*by_box*")) # doctest: +NORMALIZE_WHITESPACE ['Vect_select_areas_by_box', 'Vect_select_isles_by_box', 'Vect_select_lines_by_box', 'Vect_select_nodes_by_box'] @@ -120,9 +121,9 @@ def rename(oldname, newname, maptype, **kwargs): def copy(existingmap, newmap, maptype, **kwargs): """Copy a map - >>> copy(test_vector_name, 'mycensus', 'vector') - >>> rename('mycensus', 'mynewcensus', 'vector') - >>> remove('mynewcensus', 'vector') + >>> copy(test_vector_name, "mycensus", "vector") + >>> rename("mycensus", "mynewcensus", "vector") + >>> remove("mynewcensus", "vector") """ kwargs.update({maptype: "{old},{new}".format(old=existingmap, new=newmap)}) @@ -176,13 +177,13 @@ def get_mapset_vector(mapname, mapset=""): def is_clean_name(name): """Return if the name is valid - >>> is_clean_name('census') + >>> is_clean_name("census") True - >>> is_clean_name('0census') + >>> is_clean_name("0census") True - >>> is_clean_name('census?') + >>> is_clean_name("census?") True - >>> is_clean_name('cénsus') + >>> is_clean_name("cénsus") False """ @@ -239,14 +240,30 @@ def get_raster_for_points(poi_vector, raster, column=None, region=None): Create a vector map - >>> cols = [(u'cat', 'INTEGER PRIMARY KEY'), - ... (u'value', 'double precision')] + >>> cols = [("cat", "INTEGER PRIMARY KEY"), ("value", "double precision")] >>> vect = VectorTopo("test_vect_2") - >>> vect.open("w",tab_name="test_vect_2", - ... tab_cols=cols) - >>> vect.write(Point(10, 6), cat=1, attrs=[10, ]) - >>> vect.write(Point(12, 6), cat=2, attrs=[12, ]) - >>> vect.write(Point(14, 6), cat=3, attrs=[14, ]) + >>> vect.open("w", tab_name="test_vect_2", tab_cols=cols) + >>> vect.write( + ... Point(10, 6), + ... cat=1, + ... attrs=[ + ... 10, + ... ], + ... ) + >>> vect.write( + ... Point(12, 6), + ... cat=2, + ... attrs=[ + ... 12, + ... ], + ... ) + >>> vect.write( + ... Point(14, 6), + ... cat=3, + ... attrs=[ + ... 14, + ... ], + ... ) >>> vect.table.conn.commit() >>> vect.close() @@ -260,38 +277,40 @@ def get_raster_for_points(poi_vector, raster, column=None, region=None): Sample the raster layer at the given points, return a list of values >>> l = get_raster_for_points(vect, ele, region=region) - >>> l[0] # doctest: +ELLIPSIS + >>> l[0] # doctest: +ELLIPSIS (1, 10.0, 6.0, 1) - >>> l[1] # doctest: +ELLIPSIS + >>> l[1] # doctest: +ELLIPSIS (2, 12.0, 6.0, 1) Add a new column and sample again >>> vect.open("r") - >>> vect.table.columns.add(test_raster_name,'double precision') + >>> vect.table.columns.add(test_raster_name, "double precision") >>> vect.table.conn.commit() >>> test_raster_name in vect.table.columns True >>> get_raster_for_points(vect, ele, column=test_raster_name, region=region) True - >>> vect.table.filters.select('value', test_raster_name) + >>> vect.table.filters.select("value", test_raster_name) Filters('SELECT value, Utils_test_raster FROM test_vect_2;') >>> cur = vect.table.execute() >>> r = cur.fetchall() - >>> r[0] # doctest: +ELLIPSIS + >>> r[0] # doctest: +ELLIPSIS (10.0, 1.0) - >>> r[1] # doctest: +ELLIPSIS + >>> r[1] # doctest: +ELLIPSIS (12.0, 1.0) - >>> remove('test_vect_2','vect') + >>> remove("test_vect_2", "vect") :param poi_vector: A VectorTopo object that contains points :param raster: raster object :param str column: column name to update in the attrinute table, if set to None a list of sampled values will be returned - :param region: The region to work with, if not set the current computational region will be used + :param region: The region to work with, if not set the current computational region + will be used :return: True in case of success and a specified column for update, - if column name for update was not set a list of (id, x, y, value) is returned + if column name for update was not set a list of (id, x, y, value) is + returned """ from math import isnan @@ -372,11 +391,15 @@ def set_path(modulename, dirname=None, path="."): def split_in_chunk(iterable, length=10): """Split a list in chunk. - >>> for chunk in split_in_chunk(range(25)): print (chunk) + >>> for chunk in split_in_chunk(range(25)): + ... print(chunk) + ... (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) (10, 11, 12, 13, 14, 15, 16, 17, 18, 19) (20, 21, 22, 23, 24) - >>> for chunk in split_in_chunk(range(25), 3): print (chunk) + >>> for chunk in split_in_chunk(range(25), 3): + ... print(chunk) + ... (0, 1, 2) (3, 4, 5) (6, 7, 8) diff --git a/python/grass/pygrass/vector/__init__.py b/python/grass/pygrass/vector/__init__.py index 4016fe34dd5..44baff75300 100644 --- a/python/grass/pygrass/vector/__init__.py +++ b/python/grass/pygrass/vector/__init__.py @@ -2,12 +2,11 @@ import grass.lib.gis as libgis libgis.G_gisinit("") + import grass.lib.vector as libvect import ctypes -# # import pygrass modules -# from grass.pygrass.vector.vector_type import VTYPE from grass.pygrass.errors import GrassError, must_be_open from grass.pygrass.gis import Location @@ -78,14 +77,14 @@ def __iter__(self): """:: >>> test_vect = Vector(test_vector_name) - >>> test_vect.open(mode='r') + >>> test_vect.open(mode="r") >>> features = [feature for feature in test_vect] >>> features[:3] [Point(10.000000, 6.000000), Point(12.000000, 6.000000), Point(14.000000, 6.000000)] >>> test_vect.close() .. - """ + """ # noqa: E501 # return (self.read(f_id) for f_id in xrange(self.num_of_features())) return self @@ -94,7 +93,7 @@ def __next__(self): """:: >>> test_vect = Vector(test_vector_name) - >>> test_vect.open(mode='r') + >>> test_vect.open(mode="r") >>> test_vect.next() Point(10.000000, 6.000000) >>> test_vect.next() @@ -133,18 +132,17 @@ def write(self, geo_obj, cat=None, attrs=None): Open a new vector map :: - >>> new = VectorTopo('newvect') + >>> new = VectorTopo("newvect") >>> new.exist() False define the new columns of the attribute table :: - >>> cols = [(u'cat', 'INTEGER PRIMARY KEY'), - ... (u'name', 'TEXT')] + >>> cols = [("cat", "INTEGER PRIMARY KEY"), ("name", "TEXT")] open the vector map in write mode - >>> new.open('w', tab_name='newvect', tab_cols=cols) + >>> new.open("w", tab_name="newvect", tab_cols=cols) import a geometry feature :: @@ -157,8 +155,8 @@ def write(self, geo_obj, cat=None, attrs=None): then write the two points on the map, with :: - >>> new.write(point0, cat=1, attrs=('pub',)) - >>> new.write(point1, cat=2, attrs=('resturant',)) + >>> new.write(point0, cat=1, attrs=("pub",)) + >>> new.write(point1, cat=2, attrs=("resturant",)) commit the db changes :: @@ -174,14 +172,14 @@ def write(self, geo_obj, cat=None, attrs=None): then play with the map :: - >>> new.open(mode='r') + >>> new.open(mode="r") >>> new.read(1) Point(0.000000, 0.000000) >>> new.read(2) Point(1.000000, 1.000000) - >>> new.read(1).attrs['name'] + >>> new.read(1).attrs["name"] 'pub' - >>> new.read(2).attrs['name'] + >>> new.read(2).attrs["name"] 'resturant' >>> new.close() >>> new.remove() @@ -241,22 +239,22 @@ def has_color_table(self): Color table stored in the vector's attribute table well be not checked >>> test_vect = Vector(test_vector_name) - >>> test_vect.open(mode='r') + >>> test_vect.open(mode="r") >>> test_vect.has_color_table() False >>> test_vect.close() >>> from grass.pygrass.utils import copy, remove - >>> copy(test_vector_name,'mytest_vect','vect') + >>> copy(test_vector_name, "mytest_vect", "vect") >>> from grass.pygrass.modules.shortcuts import vector as v - >>> v.colors(map='mytest_vect', color='population', column='value') + >>> v.colors(map="mytest_vect", color="population", column="value") Module('v.colors') - >>> mytest_vect = Vector('mytest_vect') - >>> mytest_vect.open(mode='r') + >>> mytest_vect = Vector("mytest_vect") + >>> mytest_vect.open(mode="r") >>> mytest_vect.has_color_table() True >>> mytest_vect.close() - >>> remove('mytest_vect', 'vect') + >>> remove("mytest_vect", "vect") """ loc = Location() path = join(loc.path(), self.mapset, "vector", self.name, "colr") @@ -273,9 +271,9 @@ class VectorTopo(Vector): Open a vector map using the *with statement*: :: - >>> with VectorTopo(test_vector_name, mode='r') as test_vect: + >>> with VectorTopo(test_vector_name, mode="r") as test_vect: ... for feature in test_vect[:7]: - ... print(feature.attrs['name']) + ... print(feature.attrs["name"]) ... point point @@ -301,13 +299,13 @@ def __getitem__(self, key): """:: >>> test_vect = VectorTopo(test_vector_name) - >>> test_vect.open(mode='r') + >>> test_vect.open(mode="r") >>> test_vect[:4] [Point(10.000000, 6.000000), Point(12.000000, 6.000000), Point(14.000000, 6.000000)] >>> test_vect.close() .. - """ + """ # noqa: E501 if isinstance(key, slice): return [ self.read(indx) @@ -342,14 +340,14 @@ def num_primitive_of(self, primitive): :: >>> test_vect = VectorTopo(test_vector_name) - >>> test_vect.open(mode='r') - >>> test_vect.num_primitive_of('point') + >>> test_vect.open(mode="r") + >>> test_vect.num_primitive_of("point") 3 - >>> test_vect.num_primitive_of('line') + >>> test_vect.num_primitive_of("line") 3 - >>> test_vect.num_primitive_of('centroid') + >>> test_vect.num_primitive_of("centroid") 4 - >>> test_vect.num_primitive_of('boundary') + >>> test_vect.num_primitive_of("boundary") 11 >>> test_vect.close() @@ -369,7 +367,7 @@ def number_of(self, vtype): :type vtype: str >>> test_vect = VectorTopo(test_vector_name) - >>> test_vect.open(mode='r') + >>> test_vect.open(mode="r") >>> test_vect.number_of("areas") 4 >>> test_vect.number_of("islands") @@ -381,7 +379,7 @@ def number_of(self, vtype): >>> test_vect.number_of("nodes") 15 >>> test_vect.number_of("pizza") - ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE + ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE Traceback (most recent call last): ... ValueError: vtype not supported, use one of: 'areas', ... @@ -421,9 +419,9 @@ def viter(self, vtype, idonly=False): full features :type idonly: bool - >>> test_vect = VectorTopo(test_vector_name, mode='r') - >>> test_vect.open(mode='r') - >>> areas = [area for area in test_vect.viter('areas')] + >>> test_vect = VectorTopo(test_vector_name, mode="r") + >>> test_vect.open(mode="r") + >>> areas = [area for area in test_vect.viter("areas")] >>> areas[:3] [Area(1), Area(2), Area(3)] @@ -431,16 +429,17 @@ def viter(self, vtype, idonly=False): to sort the result in a efficient way, use: :: >>> from operator import methodcaller as method - >>> areas.sort(key=method('area'), reverse=True) # sort the list + >>> areas.sort(key=method("area"), reverse=True) # sort the list >>> for area in areas[:3]: ... print(area, area.area()) Area(1) 12.0 Area(2) 8.0 Area(4) 8.0 - >>> areas = [area for area in test_vect.viter('areas')] + >>> areas = [area for area in test_vect.viter("areas")] >>> for area in areas: ... print(area.centroid().cat) + ... 3 3 3 @@ -473,7 +472,7 @@ def rewind(self): """Rewind vector map to cause reads to start at beginning. :: >>> test_vect = VectorTopo(test_vector_name) - >>> test_vect.open(mode='r') + >>> test_vect.open(mode="r") >>> test_vect.next() Point(10.000000, 6.000000) >>> test_vect.next() @@ -546,8 +545,8 @@ def read(self, feature_id): :param int feature_id: the id of feature to obtain >>> test_vect = VectorTopo(test_vector_name) - >>> test_vect.open(mode='r') - >>> feature1 = test_vect.read(0) #doctest: +ELLIPSIS + >>> test_vect.open(mode="r") + >>> feature1 = test_vect.read(0) # doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: The index must be >0, 0 given. @@ -562,13 +561,13 @@ def read(self, feature_id): 21 >>> test_vect.read(21) Centroid(7.500000, 3.500000) - >>> test_vect.read(22) #doctest: +ELLIPSIS + >>> test_vect.read(22) # doctest: +ELLIPSIS Traceback (most recent call last): ... IndexError: Index out of range >>> test_vect.close() - """ + """ # noqa: E501 return read_line( feature_id, self.c_mapinfo, @@ -592,14 +591,12 @@ def is_empty(self): def rewrite(self, geo_obj, cat, attrs=None, **kargs): """Rewrite a geometry features - >>> cols = [(u'cat', 'INTEGER PRIMARY KEY'), - ... (u'name', 'TEXT')] + >>> cols = [("cat", "INTEGER PRIMARY KEY"), ("name", "TEXT")] Generate a new vector map - >>> test_vect = VectorTopo('newvect_2') - >>> test_vect.open('w', tab_name='newvect_2', tab_cols=cols, - ... overwrite=True) + >>> test_vect = VectorTopo("newvect_2") + >>> test_vect.open("w", tab_name="newvect_2", tab_cols=cols, overwrite=True) import a geometry feature :: @@ -613,8 +610,8 @@ def rewrite(self, geo_obj, cat, attrs=None, **kargs): then write the two points on the map, with :: - >>> test_vect.write(point0, cat=1, attrs=('pub',)) - >>> test_vect.write(point1, cat=2, attrs=('resturant',)) + >>> test_vect.write(point0, cat=1, attrs=("pub",)) + >>> test_vect.write(point1, cat=2, attrs=("resturant",)) >>> test_vect.table.conn.commit() # save changes in the DB >>> test_vect.table_to_dict() {1: [1, 'pub'], 2: [2, 'resturant']} @@ -622,17 +619,17 @@ def rewrite(self, geo_obj, cat, attrs=None, **kargs): Now rewrite one point of the vector map: :: - >>> test_vect.open('rw') - >>> test_vect.rewrite(point2, cat=1, attrs=('Irish Pub',)) + >>> test_vect.open("rw") + >>> test_vect.rewrite(point2, cat=1, attrs=("Irish Pub",)) >>> test_vect.table.conn.commit() # save changes in the DB >>> test_vect.close() Check the output: - >>> test_vect.open('r') + >>> test_vect.open("r") >>> test_vect[1] == point2 True - >>> test_vect[1].attrs['name'] == 'Irish Pub' + >>> test_vect[1].attrs["name"] == "Irish Pub" True >>> test_vect.close() >>> test_vect.remove() @@ -701,7 +698,7 @@ def table_to_dict(self, where=None): >>> from grass.pygrass.vector import VectorTopo >>> from grass.pygrass.vector.basic import Bbox >>> test_vect = VectorTopo(test_vector_name) - >>> test_vect.open('r') + >>> test_vect.open("r") >>> test_vect.table_to_dict() {1: [1, 'point', 1.0], 2: [2, 'line', 2.0], 3: [3, 'centroid', 3.0]} @@ -772,58 +769,56 @@ def features_to_wkb_list(self, bbox=None, feature_type="point", field=1): >>> from grass.pygrass.vector import VectorTopo >>> from grass.pygrass.vector.basic import Bbox >>> test_vect = VectorTopo(test_vector_name) - >>> test_vect.open('r') + >>> test_vect.open("r") >>> bbox = Bbox(north=20, south=-1, east=20, west=-1) - >>> result = test_vect.features_to_wkb_list(bbox=bbox, - ... feature_type="point") + >>> result = test_vect.features_to_wkb_list(bbox=bbox, feature_type="point") >>> len(result) 3 >>> for entry in result: ... f_id, cat, wkb = entry ... print((f_id, cat, len(wkb))) + ... (1, 1, 21) (2, 1, 21) (3, 1, 21) - >>> result = test_vect.features_to_wkb_list(bbox=None, - ... feature_type="line") + >>> result = test_vect.features_to_wkb_list(bbox=None, feature_type="line") >>> len(result) 3 >>> for entry in result: ... f_id, cat, wkb = entry ... print((f_id, cat, len(wkb))) + ... (4, 2, 57) (5, 2, 57) (6, 2, 57) - >>> result = test_vect.features_to_wkb_list(bbox=bbox, - ... feature_type="boundary") + >>> result = test_vect.features_to_wkb_list(bbox=bbox, feature_type="boundary") >>> len(result) 11 - >>> result = test_vect.features_to_wkb_list(bbox=None, - ... feature_type="centroid") + >>> result = test_vect.features_to_wkb_list(bbox=None, feature_type="centroid") >>> len(result) 4 >>> for entry in result: ... f_id, cat, wkb = entry ... print((f_id, cat, len(wkb))) + ... (19, 3, 21) (18, 3, 21) (20, 3, 21) (21, 3, 21) - >>> result = test_vect.features_to_wkb_list(bbox=bbox, - ... feature_type="blub") + >>> result = test_vect.features_to_wkb_list(bbox=bbox, feature_type="blub") Traceback (most recent call last): ... grass.exceptions.GrassError: Unsupported feature type , supported are >>> test_vect.close() - """ + """ # noqa: E501 supported = ["point", "line", "boundary", "centroid"] @@ -905,7 +900,7 @@ def areas_to_wkb_list(self, bbox=None, field=1): >>> from grass.pygrass.vector import VectorTopo >>> from grass.pygrass.vector.basic import Bbox >>> test_vect = VectorTopo(test_vector_name) - >>> test_vect.open('r') + >>> test_vect.open("r") >>> bbox = Bbox(north=20, south=-1, east=20, west=-1) >>> result = test_vect.areas_to_wkb_list(bbox=bbox) @@ -914,6 +909,7 @@ def areas_to_wkb_list(self, bbox=None, field=1): >>> for entry in result: ... a_id, cat, wkb = entry ... print((a_id, cat, len(wkb))) + ... (1, 3, 225) (2, 3, 141) (3, 3, 93) @@ -925,6 +921,7 @@ def areas_to_wkb_list(self, bbox=None, field=1): >>> for entry in result: ... a_id, cat, wkb = entry ... print((a_id, cat, len(wkb))) + ... (1, 3, 225) (2, 3, 141) (3, 3, 93) diff --git a/python/grass/pygrass/vector/abstract.py b/python/grass/pygrass/vector/abstract.py index e1dda3a8d7d..bafbb006d6c 100644 --- a/python/grass/pygrass/vector/abstract.py +++ b/python/grass/pygrass/vector/abstract.py @@ -3,6 +3,7 @@ @author: pietro """ + import ctypes import datetime import grass.lib.vector as libvect diff --git a/python/grass/pygrass/vector/basic.py b/python/grass/pygrass/vector/basic.py index 8917629ca43..2b8c013b433 100644 --- a/python/grass/pygrass/vector/basic.py +++ b/python/grass/pygrass/vector/basic.py @@ -3,6 +3,7 @@ @author: pietro """ + import ctypes import grass.lib.vector as libvect from collections.abc import Iterable diff --git a/python/grass/pygrass/vector/find.py b/python/grass/pygrass/vector/find.py index ac56265447c..50599af5ab5 100644 --- a/python/grass/pygrass/vector/find.py +++ b/python/grass/pygrass/vector/find.py @@ -3,6 +3,7 @@ @author: pietro """ + import grass.lib.vector as libvect from grass.pygrass.errors import must_be_open diff --git a/python/grass/pygrass/vector/geometry.py b/python/grass/pygrass/vector/geometry.py index 81d9f3a8d78..855f374b47e 100644 --- a/python/grass/pygrass/vector/geometry.py +++ b/python/grass/pygrass/vector/geometry.py @@ -3,6 +3,7 @@ @author: pietro """ + import ctypes import re from collections import namedtuple diff --git a/python/grass/pygrass/vector/table.py b/python/grass/pygrass/vector/table.py index e4f6de52ab4..48badee09f0 100644 --- a/python/grass/pygrass/vector/table.py +++ b/python/grass/pygrass/vector/table.py @@ -38,17 +38,28 @@ def get_path(path, vect_name=None): >>> from grass.script.core import gisenv >>> import os - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" >>> new_path = get_path(path) - >>> new_path2 = os.path.join(gisenv()['GISDBASE'], gisenv()['LOCATION_NAME'], - ... gisenv()['MAPSET'], 'sqlite', 'sqlite.db') - >>> new_path.replace("//","/") == new_path2.replace("//","/") + >>> new_path2 = os.path.join( + ... gisenv()["GISDBASE"], + ... gisenv()["LOCATION_NAME"], + ... gisenv()["MAPSET"], + ... "sqlite", + ... "sqlite.db", + ... ) + >>> new_path.replace("//", "/") == new_path2.replace("//", "/") True - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/vector/$MAP/sqlite.db' + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/vector/$MAP/sqlite.db" >>> new_path = get_path(path, "test") - >>> new_path2 = os.path.join(gisenv()['GISDBASE'], gisenv()['LOCATION_NAME'], - ... gisenv()['MAPSET'], 'vector', 'test', 'sqlite.db') - >>> new_path.replace("//","/") == new_path2.replace("//","/") + >>> new_path2 = os.path.join( + ... gisenv()["GISDBASE"], + ... gisenv()["LOCATION_NAME"], + ... gisenv()["MAPSET"], + ... "vector", + ... "test", + ... "sqlite.db", + ... ) + >>> new_path.replace("//", "/") == new_path2.replace("//", "/") True """ @@ -67,7 +78,7 @@ def get_path(path, vect_name=None): class Filters: """Help user to build a simple sql query. - >>> filter = Filters('table') + >>> filter = Filters("table") >>> filter.get_sql() 'SELECT * FROM table;' >>> filter.where("area<10000").get_sql() @@ -172,18 +183,18 @@ class Columns: For a sqlite table: >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' - >>> cols_sqlite = Columns(test_vector_name, - ... sqlite3.connect(get_path(path))) + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" + >>> cols_sqlite = Columns(test_vector_name, sqlite3.connect(get_path(path))) >>> cols_sqlite.tname 'table_doctest_map' For a postgreSQL table: - >>> import psycopg2 as pg #doctest: +SKIP - >>> cols_pg = Columns(test_vector_name, - ... pg.connect('host=localhost dbname=grassdb')) #doctest: +SKIP - >>> cols_pg.tname #doctest: +SKIP + >>> import psycopg2 as pg # doctest: +SKIP + >>> cols_pg = Columns( + ... test_vector_name, pg.connect("host=localhost dbname=grassdb") + ... ) # doctest: +SKIP + >>> cols_pg.tname # doctest: +SKIP 'table_doctest_map' #doctest: +SKIP """ @@ -218,7 +229,7 @@ def __eq__(self, obj): """Return True if two table have the same columns. >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" >>> connection = sqlite3.connect(get_path(path)) >>> cols0 = Columns(test_vector_name, connection) >>> cols1 = Columns(test_vector_name, connection) @@ -237,15 +248,15 @@ def is_pg(self): """Return True if is a psycopg connection. >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' - >>> cols_sqlite = Columns(test_vector_name, - ... sqlite3.connect(get_path(path))) + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" + >>> cols_sqlite = Columns(test_vector_name, sqlite3.connect(get_path(path))) >>> cols_sqlite.is_pg() False - >>> import psycopg2 as pg #doctest: +SKIP - >>> cols_pg = Columns(test_vector_name, - ... pg.connect('host=localhost dbname=grassdb')) #doctest: +SKIP - >>> cols_pg.is_pg() #doctest: +SKIP + >>> import psycopg2 as pg # doctest: +SKIP + >>> cols_pg = Columns( + ... test_vector_name, pg.connect("host=localhost dbname=grassdb") + ... ) # doctest: +SKIP + >>> cols_pg.is_pg() # doctest: +SKIP True """ @@ -300,15 +311,15 @@ def sql_descr(self, remove=None): Remove it is used to remove a columns. >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' - >>> cols_sqlite = Columns(test_vector_name, - ... sqlite3.connect(get_path(path))) - >>> cols_sqlite.sql_descr() # doctest: +ELLIPSIS + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" + >>> cols_sqlite = Columns(test_vector_name, sqlite3.connect(get_path(path))) + >>> cols_sqlite.sql_descr() # doctest: +ELLIPSIS 'cat INTEGER, name varchar(50), value double precision' - >>> import psycopg2 as pg # doctest: +SKIP - >>> cols_pg = Columns(test_vector_name, - ... pg.connect('host=localhost dbname=grassdb')) # doctest: +SKIP - >>> cols_pg.sql_descr() # doctest: +ELLIPSIS +SKIP + >>> import psycopg2 as pg # doctest: +SKIP + >>> cols_pg = Columns( + ... test_vector_name, pg.connect("host=localhost dbname=grassdb") + ... ) # doctest: +SKIP + >>> cols_pg.sql_descr() # doctest: +ELLIPSIS +SKIP 'cat INTEGER, name varchar(50), value double precision' """ if remove: @@ -322,15 +333,15 @@ def types(self): """Return a list with the column types. >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' - >>> cols_sqlite = Columns(test_vector_name, - ... sqlite3.connect(get_path(path))) - >>> cols_sqlite.types() # doctest: +ELLIPSIS + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" + >>> cols_sqlite = Columns(test_vector_name, sqlite3.connect(get_path(path))) + >>> cols_sqlite.types() # doctest: +ELLIPSIS ['INTEGER', 'varchar(50)', 'double precision'] - >>> import psycopg2 as pg # doctest: +SKIP - >>> cols_pg = Columns(test_vector_name, - ... pg.connect('host=localhost dbname=grassdb')) # doctest: +SKIP - >>> cols_pg.types() # doctest: +ELLIPSIS +SKIP + >>> import psycopg2 as pg # doctest: +SKIP + >>> cols_pg = Columns( + ... test_vector_name, pg.connect("host=localhost dbname=grassdb") + ... ) # doctest: +SKIP + >>> cols_pg.types() # doctest: +ELLIPSIS +SKIP ['INTEGER', 'varchar(50)', 'double precision'] """ @@ -341,15 +352,16 @@ def names(self, remove=None, unicod=True): Remove it is used to remove a columns. >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' - >>> cols_sqlite = Columns(test_vector_name, - ... sqlite3.connect(get_path(path))) - >>> cols_sqlite.names() # doctest: +ELLIPSIS + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" + >>> cols_sqlite = Columns(test_vector_name, sqlite3.connect(get_path(path))) + >>> cols_sqlite.names() # doctest: +ELLIPSIS ['cat', 'name', 'value'] - >>> import psycopg2 as pg # doctest: +SKIP - >>> cols_pg = Columns(test_vector_name, # doctest: +SKIP - ... pg.connect('host=localhost dbname=grassdb')) - >>> cols_pg.names() # doctest: +ELLIPSIS +SKIP + >>> import psycopg2 as pg # doctest: +SKIP + >>> cols_pg = Columns( + ... test_vector_name, # doctest: +SKIP + ... pg.connect("host=localhost dbname=grassdb"), + ... ) + >>> cols_pg.names() # doctest: +ELLIPSIS +SKIP ['cat', 'name', 'value'] """ @@ -367,15 +379,15 @@ def items(self): """Return a list of tuple with column name and column type. >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' - >>> cols_sqlite = Columns(test_vector_name, - ... sqlite3.connect(get_path(path))) - >>> cols_sqlite.items() # doctest: +ELLIPSIS + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" + >>> cols_sqlite = Columns(test_vector_name, sqlite3.connect(get_path(path))) + >>> cols_sqlite.items() # doctest: +ELLIPSIS [('cat', 'INTEGER'), ('name', 'varchar(50)'), ('value', 'double precision')] - >>> import psycopg2 as pg # doctest: +SKIP - >>> cols_pg = Columns(test_vector_name, - ... pg.connect('host=localhost dbname=grassdb')) # doctest: +SKIP - >>> cols_pg.items() # doctest: +ELLIPSIS +SKIP + >>> import psycopg2 as pg # doctest: +SKIP + >>> cols_pg = Columns( + ... test_vector_name, pg.connect("host=localhost dbname=grassdb") + ... ) # doctest: +SKIP + >>> cols_pg.items() # doctest: +ELLIPSIS +SKIP [('cat', 'INTEGER'), ('name', 'varchar(50)'), ('value', 'double precision')] """ @@ -390,21 +402,21 @@ def add(self, col_name, col_type): :type col_type: str >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" >>> from grass.pygrass.utils import copy, remove - >>> copy(test_vector_name,'mycensus','vect') - >>> cols_sqlite = Columns('mycensus', - ... sqlite3.connect(get_path(path))) - >>> cols_sqlite.add(['n_pizza'], ['INT']) - >>> 'n_pizza' in cols_sqlite + >>> copy(test_vector_name, "mycensus", "vect") + >>> cols_sqlite = Columns("mycensus", sqlite3.connect(get_path(path))) + >>> cols_sqlite.add(["n_pizza"], ["INT"]) + >>> "n_pizza" in cols_sqlite True - >>> import psycopg2 as pg # doctest: +SKIP - >>> cols_pg = Columns('boundary_municp_pg', - ... pg.connect('host=localhost dbname=grassdb')) #doctest: +SKIP - >>> cols_pg.add('n_pizza', 'INT') # doctest: +SKIP - >>> 'n_pizza' in cols_pg # doctest: +SKIP + >>> import psycopg2 as pg # doctest: +SKIP + >>> cols_pg = Columns( + ... "boundary_municp_pg", pg.connect("host=localhost dbname=grassdb") + ... ) # doctest: +SKIP + >>> cols_pg.add("n_pizza", "INT") # doctest: +SKIP + >>> "n_pizza" in cols_pg # doctest: +SKIP True - >>> remove('mycensus', 'vect') + >>> remove("mycensus", "vect") """ @@ -462,29 +474,29 @@ def rename(self, old_name, new_name): :type new_name: str >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" >>> from grass.pygrass.utils import copy, remove - >>> copy(test_vector_name,'mycensus','vect') - >>> cols_sqlite = Columns('mycensus', - ... sqlite3.connect(get_path(path))) - >>> cols_sqlite.add(['n_pizza'], ['INT']) - >>> 'n_pizza' in cols_sqlite + >>> copy(test_vector_name, "mycensus", "vect") + >>> cols_sqlite = Columns("mycensus", sqlite3.connect(get_path(path))) + >>> cols_sqlite.add(["n_pizza"], ["INT"]) + >>> "n_pizza" in cols_sqlite True - >>> cols_sqlite.rename('n_pizza', 'n_pizzas') # doctest: +ELLIPSIS - >>> 'n_pizza' in cols_sqlite + >>> cols_sqlite.rename("n_pizza", "n_pizzas") # doctest: +ELLIPSIS + >>> "n_pizza" in cols_sqlite False - >>> 'n_pizzas' in cols_sqlite + >>> "n_pizzas" in cols_sqlite True - >>> import psycopg2 as pg # doctest: +SKIP - >>> cols_pg = Columns(test_vector_name, - ... pg.connect('host=localhost dbname=grassdb')) # doctest: +SKIP - >>> cols_pg.rename('n_pizza', 'n_pizzas') # doctest: +SKIP - >>> 'n_pizza' in cols_pg # doctest: +SKIP + >>> import psycopg2 as pg # doctest: +SKIP + >>> cols_pg = Columns( + ... test_vector_name, pg.connect("host=localhost dbname=grassdb") + ... ) # doctest: +SKIP + >>> cols_pg.rename("n_pizza", "n_pizzas") # doctest: +SKIP + >>> "n_pizza" in cols_pg # doctest: +SKIP False - >>> 'n_pizzas' in cols_pg # doctest: +SKIP + >>> "n_pizzas" in cols_pg # doctest: +SKIP True - >>> remove('mycensus', 'vect') + >>> remove("mycensus", "vect") """ cur = self.conn.cursor() @@ -520,23 +532,23 @@ def cast(self, col_name, new_type): :type new_type: str >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" >>> from grass.pygrass.utils import copy, remove - >>> copy(test_vector_name,'mycensus','vect') - >>> cols_sqlite = Columns('mycensus', - ... sqlite3.connect(get_path(path))) - >>> cols_sqlite.add(['n_pizzas'], ['INT']) - >>> cols_sqlite.cast('n_pizzas', 'float8') # doctest: +ELLIPSIS + >>> copy(test_vector_name, "mycensus", "vect") + >>> cols_sqlite = Columns("mycensus", sqlite3.connect(get_path(path))) + >>> cols_sqlite.add(["n_pizzas"], ["INT"]) + >>> cols_sqlite.cast("n_pizzas", "float8") # doctest: +ELLIPSIS Traceback (most recent call last): ... grass.exceptions.DBError: SQLite does not support to cast columns. - >>> import psycopg2 as pg # doctest: +SKIP - >>> cols_pg = Columns(test_vector_name, - ... pg.connect('host=localhost dbname=grassdb')) # doctest: +SKIP - >>> cols_pg.cast('n_pizzas', 'float8') # doctest: +SKIP - >>> cols_pg['n_pizzas'] # doctest: +SKIP + >>> import psycopg2 as pg # doctest: +SKIP + >>> cols_pg = Columns( + ... test_vector_name, pg.connect("host=localhost dbname=grassdb") + ... ) # doctest: +SKIP + >>> cols_pg.cast("n_pizzas", "float8") # doctest: +SKIP + >>> cols_pg["n_pizzas"] # doctest: +SKIP 'float8' - >>> remove('mycensus', 'vect') + >>> remove("mycensus", "vect") .. warning :: @@ -562,22 +574,22 @@ def drop(self, col_name): :type col_name: str >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" >>> from grass.pygrass.utils import copy, remove - >>> copy(test_vector_name,'mycensus','vect') - >>> cols_sqlite = Columns('mycensus', - ... sqlite3.connect(get_path(path))) - >>> cols_sqlite.drop('name') # doctest: +ELLIPSIS - >>> 'name' in cols_sqlite + >>> copy(test_vector_name, "mycensus", "vect") + >>> cols_sqlite = Columns("mycensus", sqlite3.connect(get_path(path))) + >>> cols_sqlite.drop("name") # doctest: +ELLIPSIS + >>> "name" in cols_sqlite False - >>> import psycopg2 as pg # doctest: +SKIP - >>> cols_pg = Columns(test_vector_name, - ... pg.connect('host=localhost dbname=grassdb')) # doctest: +SKIP - >>> cols_pg.drop('name') # doctest: +SKIP - >>> 'name' in cols_pg # doctest: +SKIP + >>> import psycopg2 as pg # doctest: +SKIP + >>> cols_pg = Columns( + ... test_vector_name, pg.connect("host=localhost dbname=grassdb") + ... ) # doctest: +SKIP + >>> cols_pg.drop("name") # doctest: +SKIP + >>> "name" in cols_pg # doctest: +SKIP False - >>> remove('mycensus','vect') + >>> remove("mycensus", "vect") """ cur = self.conn.cursor() @@ -602,8 +614,14 @@ class Link: It is possible to define a Link object or given all the information (layer, name, table name, key, database, driver): - >>> link = Link(1, 'link0', test_vector_name, 'cat', - ... '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db', 'sqlite') + >>> link = Link( + ... 1, + ... "link0", + ... test_vector_name, + ... "cat", + ... "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db", + ... "sqlite", + ... ) >>> link.layer 1 >>> link.name @@ -622,16 +640,16 @@ class Link: It is possible to change parameters with: - >>> link.driver = 'pg' # doctest: +SKIP - >>> link.driver # doctest: +SKIP + >>> link.driver = "pg" # doctest: +SKIP + >>> link.driver # doctest: +SKIP 'pg' - >>> link.driver = 'postgres' # doctest: +ELLIPSIS +SKIP + >>> link.driver = "postgres" # doctest: +ELLIPSIS +SKIP Traceback (most recent call last): ... TypeError: Driver not supported, use: sqlite, pg. - >>> link.driver # doctest: +SKIP + >>> link.driver # doctest: +SKIP 'pg' - >>> link.number = 0 # doctest: +ELLIPSIS +SKIP + >>> link.number = 0 # doctest: +ELLIPSIS +SKIP Traceback (most recent call last): ... TypeError: Number must be positive and greater than 0. @@ -640,7 +658,7 @@ class Link: Or given a c_fieldinfo object that is a ctypes pointer to the field_info C struct. :: - >>> link = Link(c_fieldinfo = ctypes.pointer(libvect.field_info())) + >>> link = Link(c_fieldinfo=ctypes.pointer(libvect.field_info())) """ @@ -743,12 +761,30 @@ def __repr__(self): def __eq__(self, link): """Return True if two Link instance have the same parameters. - >>> l0 = Link(1, 'link0', test_vector_name, 'cat', - ... '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db', 'sqlite') - >>> l1 = Link(1, 'link0', test_vector_name, 'cat', - ... '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db', 'sqlite') - >>> l2 = Link(2, 'link0', test_vector_name, 'cat', - ... '$GISDBASE/$LOCATION_NAME/PERMANENT/sqlite/sqlite.db', 'sqlite') + >>> l0 = Link( + ... 1, + ... "link0", + ... test_vector_name, + ... "cat", + ... "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db", + ... "sqlite", + ... ) + >>> l1 = Link( + ... 1, + ... "link0", + ... test_vector_name, + ... "cat", + ... "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db", + ... "sqlite", + ... ) + >>> l2 = Link( + ... 2, + ... "link0", + ... test_vector_name, + ... "cat", + ... "$GISDBASE/$LOCATION_NAME/PERMANENT/sqlite/sqlite.db", + ... "sqlite", + ... ) >>> l0 == l1 True >>> l1 == l2 @@ -769,17 +805,23 @@ def __ne__(self, other): def connection(self): """Return a connection object. - >>> link = Link(1, 'link0', test_vector_name, 'cat', - ... '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db', - ... 'sqlite') + >>> link = Link( + ... 1, + ... "link0", + ... test_vector_name, + ... "cat", + ... "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db", + ... "sqlite", + ... ) >>> conn = link.connection() >>> cur = conn.cursor() >>> link.table_name 'table_doctest_map' - >>> cur.execute("SELECT cat, name, value from %s" % - ... link.table_name) # doctest: +ELLIPSIS + >>> cur.execute( + ... "SELECT cat, name, value from %s" % link.table_name + ... ) # doctest: +ELLIPSIS - >>> cur.fetchone() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE + >>> cur.fetchone() # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE (1, 'point', 1.0) >>> cur.close() >>> conn.close() @@ -825,11 +867,16 @@ def connection(self): def table(self): """Return a Table object. - >>> link = Link(1, 'link0', test_vector_name, 'cat', - ... '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db', - ... 'sqlite') + >>> link = Link( + ... 1, + ... "link0", + ... test_vector_name, + ... "cat", + ... "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db", + ... "sqlite", + ... ) >>> table = link.table() - >>> table.filters.select('cat', 'name', 'value') + >>> table.filters.select("cat", "name", "value") Filters('SELECT cat, name, value FROM table_doctest_map;') >>> cur = table.execute() >>> cur.fetchone() @@ -842,9 +889,14 @@ def table(self): def info(self): """Print information of the link. - >>> link = Link(1, 'link0', test_vector_name, 'cat', - ... '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db', - ... 'sqlite') + >>> link = Link( + ... 1, + ... "link0", + ... test_vector_name, + ... "cat", + ... "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db", + ... "sqlite", + ... ) >>> link.info() layer: 1 name: link0 @@ -867,7 +919,7 @@ class DBlinks: >>> from grass.pygrass.vector import VectorTopo >>> cens = VectorTopo(test_vector_name) - >>> cens.open(mode='r') + >>> cens.open(mode="r") >>> dblinks = DBlinks(cens.c_mapinfo) >>> dblinks DBlinks([Link(1, table_doctest_map, sqlite)]) @@ -943,14 +995,20 @@ def add(self, link): >>> from grass.pygrass.vector import VectorTopo >>> test_vect = VectorTopo(test_vector_name) - >>> test_vect.open(mode='r') + >>> test_vect.open(mode="r") >>> dblinks = DBlinks(test_vect.c_mapinfo) >>> dblinks DBlinks([Link(1, table_doctest_map, sqlite)]) - >>> link = Link(2, 'pg_link', test_vector_name, 'cat', - ... 'host=localhost dbname=grassdb', 'pg') # doctest: +SKIP - >>> dblinks.add(link) # doctest: +SKIP - >>> dblinks # doctest: +SKIP + >>> link = Link( + ... 2, + ... "pg_link", + ... test_vector_name, + ... "cat", + ... "host=localhost dbname=grassdb", + ... "pg", + ... ) # doctest: +SKIP + >>> dblinks.add(link) # doctest: +SKIP + >>> dblinks # doctest: +SKIP DBlinks([Link(1, table_doctest_map, sqlite)]) """ @@ -976,15 +1034,14 @@ def remove(self, key, force=False): >>> from grass.pygrass.vector import VectorTopo >>> test_vect = VectorTopo(test_vector_name) - >>> test_vect.open(mode='r') + >>> test_vect.open(mode="r") >>> dblinks = DBlinks(test_vect.c_mapinfo) >>> dblinks DBlinks([Link(1, table_doctest_map, sqlite)]) - >>> dblinks.remove('pg_link') # doctest: +SKIP + >>> dblinks.remove("pg_link") # doctest: +SKIP >>> dblinks # need to open vector map in write mode DBlinks([Link(1, table_doctest_map, sqlite)]) - """ if force: link = self.by_name(key) @@ -1005,16 +1062,17 @@ class Table: """ >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/PERMANENT/sqlite/sqlite.db' - >>> tab_sqlite = Table(name=test_vector_name, - ... connection=sqlite3.connect(get_path(path))) + >>> path = "$GISDBASE/$LOCATION_NAME/PERMANENT/sqlite/sqlite.db" + >>> tab_sqlite = Table( + ... name=test_vector_name, connection=sqlite3.connect(get_path(path)) + ... ) >>> tab_sqlite.name 'table_doctest_map' - >>> import psycopg2 # doctest: +SKIP - >>> tab_pg = Table(test_vector_name, - ... psycopg2.connect('host=localhost dbname=grassdb', - ... 'pg')) # doctest: +SKIP - >>> tab_pg.columns # doctest: +ELLIPSIS +SKIP + >>> import psycopg2 # doctest: +SKIP + >>> tab_pg = Table( + ... test_vector_name, psycopg2.connect("host=localhost dbname=grassdb", "pg") + ... ) # doctest: +SKIP + >>> tab_pg.columns # doctest: +ELLIPSIS +SKIP Columns([('cat', 'int4'), ...]) """ @@ -1048,9 +1106,10 @@ def __repr__(self): """ >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/PERMANENT/sqlite/sqlite.db' - >>> tab_sqlite = Table(name=test_vector_name, - ... connection=sqlite3.connect(get_path(path))) + >>> path = "$GISDBASE/$LOCATION_NAME/PERMANENT/sqlite/sqlite.db" + >>> tab_sqlite = Table( + ... name=test_vector_name, connection=sqlite3.connect(get_path(path)) + ... ) >>> tab_sqlite Table('table_doctest_map') @@ -1096,9 +1155,10 @@ def n_rows(self): """Return the number of rows >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' - >>> tab_sqlite = Table(name=test_vector_name, - ... connection=sqlite3.connect(get_path(path))) + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" + >>> tab_sqlite = Table( + ... name=test_vector_name, connection=sqlite3.connect(get_path(path)) + ... ) >>> tab_sqlite.n_rows() 3 """ @@ -1124,13 +1184,14 @@ def execute(self, sql_code=None, cursor=None, many=False, values=None): :type values: list of tuple >>> import sqlite3 - >>> path = '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db' - >>> tab_sqlite = Table(name=test_vector_name, - ... connection=sqlite3.connect(get_path(path))) - >>> tab_sqlite.filters.select('cat', 'name').order_by('value') + >>> path = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db" + >>> tab_sqlite = Table( + ... name=test_vector_name, connection=sqlite3.connect(get_path(path)) + ... ) + >>> tab_sqlite.filters.select("cat", "name").order_by("value") Filters('SELECT cat, name FROM table_doctest_map ORDER BY value;') >>> cur = tab_sqlite.execute() - >>> cur.fetchone() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE + >>> cur.fetchone() # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE (1, 'point') """ diff --git a/python/grass/pygrass/vector/testsuite/test_filters.py b/python/grass/pygrass/vector/testsuite/test_filters.py index 6d3d7247f66..9252b134c02 100644 --- a/python/grass/pygrass/vector/testsuite/test_filters.py +++ b/python/grass/pygrass/vector/testsuite/test_filters.py @@ -3,6 +3,7 @@ @author: pietro """ + from grass.gunittest.case import TestCase from grass.gunittest.main import test diff --git a/python/grass/pygrass/vector/testsuite/test_geometry.py b/python/grass/pygrass/vector/testsuite/test_geometry.py index a81c7d4a96f..d4ad7431278 100644 --- a/python/grass/pygrass/vector/testsuite/test_geometry.py +++ b/python/grass/pygrass/vector/testsuite/test_geometry.py @@ -3,6 +3,7 @@ @author: pietro """ + import sys import unittest import numpy as np diff --git a/python/grass/pygrass/vector/testsuite/test_geometry_attrs.py b/python/grass/pygrass/vector/testsuite/test_geometry_attrs.py index a1b75e0e9a6..4c17ef03d4c 100644 --- a/python/grass/pygrass/vector/testsuite/test_geometry_attrs.py +++ b/python/grass/pygrass/vector/testsuite/test_geometry_attrs.py @@ -3,6 +3,7 @@ @author: pietro """ + import sys import unittest import numpy as np diff --git a/python/grass/pygrass/vector/testsuite/test_table.py b/python/grass/pygrass/vector/testsuite/test_table.py index d80be7beb04..d603817de98 100644 --- a/python/grass/pygrass/vector/testsuite/test_table.py +++ b/python/grass/pygrass/vector/testsuite/test_table.py @@ -3,6 +3,7 @@ @author: pietro """ + import os import sqlite3 import tempfile as tmp diff --git a/python/grass/pygrass/vector/testsuite/test_vector.py b/python/grass/pygrass/vector/testsuite/test_vector.py index 12a553e02e2..a57856eca45 100644 --- a/python/grass/pygrass/vector/testsuite/test_vector.py +++ b/python/grass/pygrass/vector/testsuite/test_vector.py @@ -3,6 +3,7 @@ @author: pietro """ + from grass.gunittest.case import TestCase from grass.gunittest.main import test diff --git a/python/grass/pygrass/vector/testsuite/test_vector3d.py b/python/grass/pygrass/vector/testsuite/test_vector3d.py index 25fe46c8914..16ee0fd969e 100644 --- a/python/grass/pygrass/vector/testsuite/test_vector3d.py +++ b/python/grass/pygrass/vector/testsuite/test_vector3d.py @@ -3,6 +3,7 @@ @author: pietro """ + import numpy as np from grass.gunittest.case import TestCase diff --git a/python/grass/script/core.py b/python/grass/script/core.py index 64355616954..b1c70973cb2 100644 --- a/python/grass/script/core.py +++ b/python/grass/script/core.py @@ -766,7 +766,7 @@ def fatal(msg, env=None): if raise_on_error: raise ScriptError(msg) - error(msg, env=None) + error(msg, env=env) sys.exit(1) diff --git a/python/grass/script/db.py b/python/grass/script/db.py index 2aa2e983c78..abb7ad1764b 100644 --- a/python/grass/script/db.py +++ b/python/grass/script/db.py @@ -36,11 +36,11 @@ def db_describe(table, env=None, **args): """Return the list of columns for a database table (interface to `db.describe -c`). Example: - >>> run_command('g.copy', vector='firestations,myfirestations') + >>> run_command("g.copy", vector="firestations,myfirestations") 0 - >>> db_describe('myfirestations') # doctest: +ELLIPSIS + >>> db_describe("myfirestations") # doctest: +ELLIPSIS {'nrows': 71, 'cols': [['cat', 'INTEGER', '20'], ... 'ncols': 22} - >>> run_command('g.remove', flags='f', type='vector', name='myfirestations') + >>> run_command("g.remove", flags="f", type="vector", name="myfirestations") 0 :param str table: table name @@ -81,11 +81,11 @@ def db_table_exist(table, env=None, **args): If no driver or database are given, then default settings is used (check db_connection()). - >>> run_command('g.copy', vector='firestations,myfirestations') + >>> run_command("g.copy", vector="firestations,myfirestations") 0 - >>> db_table_exist('myfirestations') + >>> db_table_exist("myfirestations") True - >>> run_command('g.remove', flags='f', type='vector', name='myfirestations') + >>> run_command("g.remove", flags="f", type="vector", name="myfirestations") 0 :param str table: table name @@ -125,7 +125,7 @@ def db_connection(force=False, env=None): :param env: environment :return: parsed output of db.connect - """ + """ # noqa: E501 try: nuldev = open(os.devnull, "w") conn = parse_command("db.connect", flags="g", stderr=nuldev, env=env) @@ -148,16 +148,16 @@ def db_select(sql=None, filename=None, table=None, env=None, **args): Examples: - >>> run_command('g.copy', vector='firestations,myfirestations') + >>> run_command("g.copy", vector="firestations,myfirestations") 0 - >>> db_select(sql = 'SELECT cat,CITY FROM myfirestations WHERE cat < 4') + >>> db_select(sql="SELECT cat,CITY FROM myfirestations WHERE cat < 4") (('1', 'Morrisville'), ('2', 'Morrisville'), ('3', 'Apex')) Simplyfied usage (it performs SELECT * FROM myfirestations.) - >>> db_select(table = 'myfirestations') # doctest: +ELLIPSIS + >>> db_select(table="myfirestations") # doctest: +ELLIPSIS (('1', '24', 'Morrisville #3', ... 'HS2A', '1.37')) - >>> run_command('g.remove', flags='f', type='vector', name='myfirestations') + >>> run_command("g.remove", flags="f", type="vector", name="myfirestations") 0 :param str sql: SQL statement to perform (or None) @@ -176,7 +176,8 @@ def db_select(sql=None, filename=None, table=None, env=None, **args): else: fatal( _( - "Programmer error: '%(sql)s', '%(filename)s', or '%(table)s' must be provided" + "Programmer error: '%(sql)s', '%(filename)s', or '%(table)s' must be \ + provided" ) % {"sql": "sql", "filename": "filename", "table": "table"} ) @@ -203,12 +204,12 @@ def db_table_in_vector(table, mapset=".", env=None): name could be used also in other mapset by other vector. It returns None if no vectors are connected to the table. - >>> run_command('g.copy', vector='firestations,myfirestations') + >>> run_command("g.copy", vector="firestations,myfirestations") 0 - >>> db_table_in_vector('myfirestations') + >>> db_table_in_vector("myfirestations") ['myfirestations@user1'] - >>> db_table_in_vector('mfirestations') - >>> run_command('g.remove', flags='f', type='vector', name='myfirestations') + >>> db_table_in_vector("mfirestations") + >>> run_command("g.remove", flags="f", type="vector", name="myfirestations") 0 :param str table: name of table to query diff --git a/python/grass/script/task.py b/python/grass/script/task.py index 1c4e29f69a6..325b5640edc 100644 --- a/python/grass/script/task.py +++ b/python/grass/script/task.py @@ -17,6 +17,7 @@ .. sectionauthor:: Martin Landa """ + import os import re import sys diff --git a/python/grass/script/tests/grass_script_core_location_test.py b/python/grass/script/tests/grass_script_core_location_test.py index db8696cfeea..081fbb519c9 100644 --- a/python/grass/script/tests/grass_script_core_location_test.py +++ b/python/grass/script/tests/grass_script_core_location_test.py @@ -70,9 +70,6 @@ def test_without_session(tmp_path): wkt_file = tmp_path / name / "PERMANENT" / "PROJ_WKT" assert wkt_file.exists() with gs.setup.init(tmp_path / name): - gs.run_command("g.gisenv", set=f"GISDBASE={tmp_path}") - gs.run_command("g.gisenv", set=f"LOCATION_NAME={name}") - gs.run_command("g.gisenv", set="MAPSET=PERMANENT") epsg = gs.parse_command("g.proj", flags="g")["srid"] assert epsg == "EPSG:3358" @@ -109,9 +106,6 @@ def test_path_only(tmp_path): assert mapset_path.exists() assert wkt_file.exists() with gs.setup.init(full_path): - gs.run_command("g.gisenv", set=f"GISDBASE={tmp_path}") - gs.run_command("g.gisenv", set=f"LOCATION_NAME={desired_location}") - gs.run_command("g.gisenv", set="MAPSET=PERMANENT") epsg = gs.parse_command("g.proj", flags="g")["srid"] assert epsg == "EPSG:3358" @@ -123,9 +117,6 @@ def test_create_project(tmp_path): wkt_file = tmp_path / name / "PERMANENT" / "PROJ_WKT" assert wkt_file.exists() with gs.setup.init(tmp_path / name): - gs.run_command("g.gisenv", set=f"GISDBASE={tmp_path}") - gs.run_command("g.gisenv", set=f"LOCATION_NAME={name}") - gs.run_command("g.gisenv", set="MAPSET=PERMANENT") epsg = gs.parse_command("g.proj", flags="g")["srid"] assert epsg == "EPSG:3358" diff --git a/python/grass/script/vector.py b/python/grass/script/vector.py index 6b0c9efe2b2..131a872b1d4 100644 --- a/python/grass/script/vector.py +++ b/python/grass/script/vector.py @@ -16,6 +16,7 @@ .. sectionauthor:: Glynn Clements .. sectionauthor:: Martin Landa """ + import os from .utils import parse_key_val @@ -34,7 +35,7 @@ def vector_db(map, env=None, **kwargs): """Return the database connection details for a vector map (interface to `v.db.connect -g`). Example: - >>> vector_db('geology') # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >>> vector_db("geology") # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE {1: {'layer': 1, ... 'table': 'geology'}} :param str map: vector map @@ -98,7 +99,7 @@ def vector_columns(map, layer=None, getDict=True, env=None, **kwargs): """Return a dictionary (or a list) of the columns for the database table connected to a vector map (interface to `v.info -c`). - >>> vector_columns('geology', getDict=True) # doctest: +NORMALIZE_WHITESPACE + >>> vector_columns("geology", getDict=True) # doctest: +NORMALIZE_WHITESPACE {'PERIMETER': {'index': 2, 'type': 'DOUBLE PRECISION'}, 'GEOL250_': {'index': 3, 'type': 'INTEGER'}, 'SHAPE_area': {'index': 6, 'type': 'DOUBLE PRECISION'}, 'onemap_pro': {'index': 1, 'type': 'DOUBLE @@ -106,7 +107,7 @@ def vector_columns(map, layer=None, getDict=True, env=None, **kwargs): 'cat': {'index': 0, 'type': 'INTEGER'}, 'GEOL250_ID': {'index': 4, 'type': 'INTEGER'}, 'GEO_NAME': {'index': 5, 'type': 'CHARACTER'}} - >>> vector_columns('geology', getDict=False) # doctest: +NORMALIZE_WHITESPACE + >>> vector_columns("geology", getDict=False) # doctest: +NORMALIZE_WHITESPACE ['cat', 'onemap_pro', 'PERIMETER', @@ -167,7 +168,7 @@ def vector_info_topo(map, layer=1, env=None): """Return information about a vector map (interface to `v.info -t`). Example: - >>> vector_info_topo('geology') # doctest: +NORMALIZE_WHITESPACE + >>> vector_info_topo("geology") # doctest: +NORMALIZE_WHITESPACE {'lines': 0, 'centroids': 1832, 'boundaries': 3649, 'points': 0, 'primitives': 5481, 'islands': 907, 'nodes': 2724, 'map3d': False, 'areas': 1832} @@ -190,7 +191,7 @@ def vector_info(map, layer=1, env=None): """Return information about a vector map (interface to `v.info`). Example: - >>> vector_info('geology') # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >>> vector_info("geology") # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE {'comment': '', 'projection': 'Lambert Conformal Conic' ... 'south': 10875.8272320917} :param str map: map name @@ -198,7 +199,7 @@ def vector_info(map, layer=1, env=None): :param env: environment :return: parsed vector info - """ + """ # noqa: E501 s = read_command("v.info", flags="get", layer=layer, map=map, env=env) @@ -233,11 +234,11 @@ def vector_db_select(map, layer=1, env=None, **kwargs): Function returns list of columns and dictionary of values ordered by key column value. Example: - >>> print vector_db_select('geology')['columns'] + >>> print(vector_db_select("geology")["columns"]) ['cat', 'onemap_pro', 'PERIMETER', 'GEOL250_', 'GEOL250_ID', 'GEO_NAME', 'SHAPE_area', 'SHAPE_len'] - >>> print vector_db_select('geology')['values'][3] + >>> print(vector_db_select("geology")["values"][3]) ['3', '579286.875', '3335.55835', '4', '3', 'Zml', '579286.829631', '3335.557182'] - >>> print vector_db_select('geology', columns = 'GEO_NAME')['values'][3] + >>> print(vector_db_select("geology", columns="GEO_NAME")["values"][3]) ['Zml'] :param str map: map name @@ -246,7 +247,7 @@ def vector_db_select(map, layer=1, env=None, **kwargs): :param env: environment :return: dictionary ('columns' and 'values') - """ + """ # noqa: E501 try: key = vector_db(map=map, env=env)[layer]["key"] except KeyError: diff --git a/python/grass/temporal/abstract_dataset.py b/python/grass/temporal/abstract_dataset.py index 4d6d4d81b51..720b2210ad8 100644 --- a/python/grass/temporal/abstract_dataset.py +++ b/python/grass/temporal/abstract_dataset.py @@ -9,6 +9,7 @@ :authors: Soeren Gebbert """ + from abc import ABCMeta, abstractmethod from .core import ( get_tgis_message_interface, diff --git a/python/grass/temporal/abstract_map_dataset.py b/python/grass/temporal/abstract_map_dataset.py index 035e64c7622..70d325c87b4 100644 --- a/python/grass/temporal/abstract_map_dataset.py +++ b/python/grass/temporal/abstract_map_dataset.py @@ -9,6 +9,7 @@ :authors: Soeren Gebbert """ + import grass.script as gs from grass.exceptions import ImplementationError from datetime import datetime @@ -176,8 +177,8 @@ def split_name(name, layer=None, mapset=None): layer exists :param mapset: The mapset in which the map is located - :return: tuple of three elements name, layer, mapset e(:layer)@mapset" while layer is - optional + :return: tuple of three elements name, layer, mapset e(:layer)@mapset" while + layer is optional """ # Check if the name includes any mapset @@ -222,7 +223,8 @@ def build_id_from_search_path(name, element): else: gs.fatal( _( - "Map <{map_name}> of element tpye '{element}' not found on search path" + "Map <{map_name}> of element tpye '{element}' not found on \ + search path" ).format(element=element, map_name=name) ) @@ -276,25 +278,25 @@ def print_info(self): """Print information about this object in human readable style""" if self.get_type() == "raster": - # 1 2 3 4 5 6 7 - # 0123456789012345678901234567890123456789012345678901234567890123456789012345678 + # 1 2 3 4 5 6 7 # noqa: E501 + # 0123456789012345678901234567890123456789012345678901234567890123456789012345678 # noqa: E501 print( - " +-------------------- Raster Dataset ----------------------------------------+" + " +-------------------- Raster Dataset ----------------------------------------+" # noqa: E501 ) if self.get_type() == "raster3d": - # 1 2 3 4 5 6 7 - # 0123456789012345678901234567890123456789012345678901234567890123456789012345678 + # 1 2 3 4 5 6 7 # noqa: E501 + # 0123456789012345678901234567890123456789012345678901234567890123456789012345678 # noqa: E501 print( - " +-------------------- 3D Raster Dataset -------------------------------------+" + " +-------------------- 3D Raster Dataset -------------------------------------+" # noqa: E501 ) if self.get_type() == "vector": - # 1 2 3 4 5 6 7 - # 0123456789012345678901234567890123456789012345678901234567890123456789012345678 + # 1 2 3 4 5 6 7 # noqa: E501 + # 0123456789012345678901234567890123456789012345678901234567890123456789012345678 # noqa: E501 print( - " +-------------------- Vector Dataset ----------------------------------------+" + " +-------------------- Vector Dataset ----------------------------------------+" # noqa: E501 ) print( - " | |" + " | |" # noqa: E501 ) self.base.print_info() self.temporal_extent.print_info() @@ -317,7 +319,7 @@ def print_info(self): count += 1 print(" | Registered datasets ........ " + string) print( - " +----------------------------------------------------------------------------+" + " +----------------------------------------------------------------------------+" # noqa: E501 ) def print_shell_info(self): @@ -683,24 +685,32 @@ def set_temporal_extent(self, extent): >>> import datetime >>> import grass.temporal as tgis - >>> map = tgis.RasterDataset(None) - >>> temp_ext = tgis.RasterRelativeTime(start_time=1, end_time=2, unit="years") + >>> map = tgis.RasterDataset(None) + >>> temp_ext = tgis.RasterRelativeTime( + ... start_time=1, end_time=2, unit="years" + ... ) >>> map.set_temporal_extent(temp_ext) >>> print(map.get_temporal_extent_as_tuple()) (1, 2) - >>> map = tgis.VectorDataset(None) - >>> temp_ext = tgis.VectorAbsoluteTime(start_time=datetime.datetime(2000, 1, 1), - ... end_time=datetime.datetime(2001, 1, 1)) + >>> map = tgis.VectorDataset(None) + >>> temp_ext = tgis.VectorAbsoluteTime( + ... start_time=datetime.datetime(2000, 1, 1), + ... end_time=datetime.datetime(2001, 1, 1), + ... ) >>> map.set_temporal_extent(temp_ext) >>> print(map.get_temporal_extent_as_tuple()) (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0)) >>> map1 = tgis.VectorDataset("A@P") - >>> check = map1.set_absolute_time(datetime.datetime(2000,5,5), datetime.datetime(2005,6,6)) + >>> check = map1.set_absolute_time( + ... datetime.datetime(2000, 5, 5), datetime.datetime(2005, 6, 6) + ... ) >>> print(map1.get_temporal_extent_as_tuple()) (datetime.datetime(2000, 5, 5, 0, 0), datetime.datetime(2005, 6, 6, 0, 0)) >>> map2 = tgis.RasterDataset("B@P") - >>> check = map2.set_absolute_time(datetime.datetime(1990,1,1), datetime.datetime(1999,8,1)) + >>> check = map2.set_absolute_time( + ... datetime.datetime(1990, 1, 1), datetime.datetime(1999, 8, 1) + ... ) >>> print(map2.get_temporal_extent_as_tuple()) (datetime.datetime(1990, 1, 1, 0, 0), datetime.datetime(1999, 8, 1, 0, 0)) >>> map2.set_temporal_extent(map1.get_temporal_extent()) @@ -743,15 +753,17 @@ def temporal_buffer(self, increment, update=False, dbif=None): >>> import grass.temporal as tgis >>> maps = [] >>> for i in range(5): - ... map = tgis.RasterDataset(None) - ... if i%2 == 0: - ... check = map.set_relative_time(i, i + 1, 'years') - ... else: - ... check = map.set_relative_time(i, None, 'years') - ... map.temporal_buffer(3) - ... maps.append(map) + ... map = tgis.RasterDataset(None) + ... if i % 2 == 0: + ... check = map.set_relative_time(i, i + 1, "years") + ... else: + ... check = map.set_relative_time(i, None, "years") + ... map.temporal_buffer(3) + ... maps.append(map) + ... >>> for map in maps: - ... map.temporal_extent.print_info() + ... map.temporal_extent.print_info() + ... +-------------------- Relative time -----------------------------------------+ | Start time:................. -3 | End time:................... 4 @@ -773,16 +785,20 @@ def temporal_buffer(self, increment, update=False, dbif=None): | End time:................... 8 | Relative time unit:......... years >>> maps = [] - >>> for i in range(1,5): - ... map = tgis.RasterDataset(None) - ... if i%2 == 0: - ... check = map.set_absolute_time(datetime(2001,i,1), datetime(2001, i + 1, 1)) - ... else: - ... check = map.set_absolute_time(datetime(2001,i,1), None) - ... map.temporal_buffer("7 days") - ... maps.append(map) + >>> for i in range(1, 5): + ... map = tgis.RasterDataset(None) + ... if i % 2 == 0: + ... check = map.set_absolute_time( + ... datetime(2001, i, 1), datetime(2001, i + 1, 1) + ... ) + ... else: + ... check = map.set_absolute_time(datetime(2001, i, 1), None) + ... map.temporal_buffer("7 days") + ... maps.append(map) + ... >>> for map in maps: - ... map.temporal_extent.print_info() + ... map.temporal_extent.print_info() + ... +-------------------- Absolute time -----------------------------------------+ | Start time:................. 2000-12-25 00:00:00 | End time:................... 2001-01-08 00:00:00 @@ -796,7 +812,7 @@ def temporal_buffer(self, increment, update=False, dbif=None): | Start time:................. 2001-03-25 00:00:00 | End time:................... 2001-05-08 00:00:00 - """ + """ # noqa: E501 if self.is_time_absolute(): start, end = self.get_absolute_time() @@ -854,8 +870,10 @@ def set_spatial_extent(self, spatial_extent): >>> import datetime >>> import grass.temporal as tgis - >>> map = tgis.RasterDataset(None) - >>> spat_ext = tgis.SpatialExtent(north=10, south=-10, east=20, west=-20, top=5, bottom=-5) + >>> map = tgis.RasterDataset(None) + >>> spat_ext = tgis.SpatialExtent( + ... north=10, south=-10, east=20, west=-20, top=5, bottom=-5 + ... ) >>> map.set_spatial_extent(spat_ext) >>> print(map.get_spatial_extent_as_tuple()) (10.0, -10.0, 20.0, -20.0, 5.0, -5.0) @@ -876,7 +894,9 @@ def spatial_buffer(self, size, update=False, dbif=None): >>> import grass.temporal as tgis >>> map = tgis.RasterDataset(None) - >>> spat_ext = tgis.SpatialExtent(north=10, south=-10, east=20, west=-20, top=5, bottom=-5) + >>> spat_ext = tgis.SpatialExtent( + ... north=10, south=-10, east=20, west=-20, top=5, bottom=-5 + ... ) >>> map.set_spatial_extent(spat_ext) >>> map.spatial_buffer(10) >>> print(map.get_spatial_extent_as_tuple()) @@ -906,7 +926,9 @@ def spatial_buffer_2d(self, size, update=False, dbif=None): >>> import grass.temporal as tgis >>> map = tgis.RasterDataset(None) - >>> spat_ext = tgis.SpatialExtent(north=10, south=-10, east=20, west=-20, top=5, bottom=-5) + >>> spat_ext = tgis.SpatialExtent( + ... north=10, south=-10, east=20, west=-20, top=5, bottom=-5 + ... ) >>> map.set_spatial_extent(spat_ext) >>> map.spatial_buffer_2d(10) >>> print(map.get_spatial_extent_as_tuple()) diff --git a/python/grass/temporal/abstract_space_time_dataset.py b/python/grass/temporal/abstract_space_time_dataset.py index d7e28427190..38d154c9f11 100644 --- a/python/grass/temporal/abstract_space_time_dataset.py +++ b/python/grass/temporal/abstract_space_time_dataset.py @@ -9,6 +9,7 @@ class that is the base class for all space time datasets. :authors: Soeren Gebbert """ + import sys import uuid import os @@ -142,32 +143,32 @@ def print_info(self): """Print information about this class in human readable style""" if self.get_type() == "strds": - # 1 2 3 4 5 6 7 - # 0123456789012345678901234567890123456789012345678901234567890123456789012345678 + # 1 2 3 4 5 6 7 # noqa: E501 + # 0123456789012345678901234567890123456789012345678901234567890123456789012345678 # noqa: E501 print( - " +-------------------- Space Time Raster Dataset -----------------------------+" + " +-------------------- Space Time Raster Dataset -----------------------------+" # noqa: E501 ) if self.get_type() == "str3ds": - # 1 2 3 4 5 6 7 - # 0123456789012345678901234567890123456789012345678901234567890123456789012345678 + # 1 2 3 4 5 6 7 # noqa: E501 + # 0123456789012345678901234567890123456789012345678901234567890123456789012345678 # noqa: E501 print( - " +-------------------- Space Time 3D Raster Dataset --------------------------+" + " +-------------------- Space Time 3D Raster Dataset --------------------------+" # noqa: E501 ) if self.get_type() == "stvds": - # 1 2 3 4 5 6 7 - # 0123456789012345678901234567890123456789012345678901234567890123456789012345678 + # 1 2 3 4 5 6 7 # noqa: E501 + # 0123456789012345678901234567890123456789012345678901234567890123456789012345678 # noqa: E501 print( - " +-------------------- Space Time Vector Dataset -----------------------------+" + " +-------------------- Space Time Vector Dataset -----------------------------+" # noqa: E501 ) print( - " | |" + " | |" # noqa: E501 ) self.base.print_info() self.temporal_extent.print_info() self.spatial_extent.print_info() self.metadata.print_info() print( - " +----------------------------------------------------------------------------+" + " +----------------------------------------------------------------------------+" # noqa: E501 ) def print_shell_info(self): @@ -395,7 +396,8 @@ def insert(self, dbif=None, execute=True): # Create table name stds_register_table = self.create_map_register_name() # Assure that the table and index do not exist - # dbif.execute_transaction("DROP INDEX IF EXISTS %s; DROP TABLE IF EXISTS %s;"%(stds_register_table + "_index", stds_register_table)) + # dbif.execute_transaction("DROP INDEX IF EXISTS %s; DROP TABLE IF EXISTS + # %s;"%(stds_register_table + "_index", stds_register_table)) # Read the SQL template sql = open( @@ -453,7 +455,8 @@ def count_temporal_types(self, maps=None, dbif=None): - interval -> start and end time - invalid -> No valid time point or interval found - :param maps: A sorted (start_time) list of AbstractDataset objects or database rows + :param maps: A sorted (start_time) list of AbstractDataset objects or database + rows :param dbif: The database interface to be used """ @@ -635,8 +638,9 @@ def sample_by_dataset(self, stds, method=None, spatial=False, dbif=None): .. code-block:: python - list = self.sample_by_dataset(stds=sampler, method=[ - "during","overlap","contains","equal"]) + list = self.sample_by_dataset( + stds=sampler, method=["during", "overlap", "contains", "equal"] + ) for entry in list: granule = entry["granule"] maplist = entry["samples"] @@ -850,8 +854,9 @@ def sample_by_dataset_sql(self, stds, method=None, spatial=False, dbif=None): .. code-block:: python - list = self.sample_by_dataset(stds=sampler, method=[ - "during","overlap","contain","equal"]) + list = self.sample_by_dataset( + stds=sampler, method=["during", "overlap", "contain", "equal"] + ) for entry in list: granule = entry["granule"] maplist = entry["samples"] @@ -1199,12 +1204,19 @@ def resample_maplist_by_granularity(maps, start, end, gran): >>> import grass.temporal as tgis >>> maps = [] >>> for i in range(3): - ... map = tgis.RasterDataset("map%i@PERMANENT"%i) + ... map = tgis.RasterDataset("map%i@PERMANENT" % i) ... check = map.set_relative_time(i + 2, i + 3, "days") ... maps.append(map) - >>> grans = tgis.AbstractSpaceTimeDataset.resample_maplist_by_granularity(maps,0,8,1) + ... + >>> grans = tgis.AbstractSpaceTimeDataset.resample_maplist_by_granularity( + ... maps, 0, 8, 1 + ... ) >>> for map_list in grans: - ... print(map_list[0].get_id(), map_list[0].get_temporal_extent_as_tuple()) + ... print( + ... map_list[0].get_id(), + ... map_list[0].get_temporal_extent_as_tuple(), + ... ) + ... None (0, 1) None (1, 2) map0@PERMANENT (2, 3) @@ -1221,9 +1233,15 @@ def resample_maplist_by_granularity(maps, start, end, gran): >>> map2 = tgis.RasterDataset("map2@PERMANENT") >>> check = map2.set_relative_time(7, 13, "days") >>> maps.append(map2) - >>> grans = tgis.AbstractSpaceTimeDataset.resample_maplist_by_granularity(maps,0,16,2) + >>> grans = tgis.AbstractSpaceTimeDataset.resample_maplist_by_granularity( + ... maps, 0, 16, 2 + ... ) >>> for map_list in grans: - ... print(map_list[0].get_id(), map_list[0].get_temporal_extent_as_tuple()) + ... print( + ... map_list[0].get_id(), + ... map_list[0].get_temporal_extent_as_tuple(), + ... ) + ... None (0, 2) map1@PERMANENT (2, 4) map1@PERMANENT (4, 6) @@ -1240,9 +1258,15 @@ def resample_maplist_by_granularity(maps, start, end, gran): >>> map2 = tgis.RasterDataset("map2@PERMANENT") >>> check = map2.set_relative_time(7, None, "days") >>> maps.append(map2) - >>> grans = tgis.AbstractSpaceTimeDataset.resample_maplist_by_granularity(maps,0,16,2) + >>> grans = tgis.AbstractSpaceTimeDataset.resample_maplist_by_granularity( + ... maps, 0, 16, 2 + ... ) >>> for map_list in grans: - ... print(map_list[0].get_id(), map_list[0].get_temporal_extent_as_tuple()) + ... print( + ... map_list[0].get_id(), + ... map_list[0].get_temporal_extent_as_tuple(), + ... ) + ... None (0, 2) map1@PERMANENT (2, 4) None (4, 6) @@ -1254,14 +1278,24 @@ def resample_maplist_by_granularity(maps, start, end, gran): >>> maps = [] >>> map1 = tgis.RasterDataset("map1@PERMANENT") - >>> check = map1.set_absolute_time(datetime(2000, 4,1), datetime(2000, 6, 1)) + >>> check = map1.set_absolute_time( + ... datetime(2000, 4, 1), datetime(2000, 6, 1) + ... ) >>> maps.append(map1) >>> map2 = tgis.RasterDataset("map2@PERMANENT") - >>> check = map2.set_absolute_time(datetime(2000, 8,1), datetime(2000, 12, 1)) + >>> check = map2.set_absolute_time( + ... datetime(2000, 8, 1), datetime(2000, 12, 1) + ... ) >>> maps.append(map2) - >>> grans = tgis.AbstractSpaceTimeDataset.resample_maplist_by_granularity(maps,datetime(2000,1,1),datetime(2001,4,1),"1 month") + >>> grans = tgis.AbstractSpaceTimeDataset.resample_maplist_by_granularity( + ... maps, datetime(2000, 1, 1), datetime(2001, 4, 1), "1 month" + ... ) >>> for map_list in grans: - ... print(map_list[0].get_id(), map_list[0].get_temporal_extent_as_tuple()) + ... print( + ... map_list[0].get_id(), + ... map_list[0].get_temporal_extent_as_tuple(), + ... ) + ... None (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 2, 1, 0, 0)) None (datetime.datetime(2000, 2, 1, 0, 0), datetime.datetime(2000, 3, 1, 0, 0)) None (datetime.datetime(2000, 3, 1, 0, 0), datetime.datetime(2000, 4, 1, 0, 0)) @@ -1278,7 +1312,7 @@ def resample_maplist_by_granularity(maps, start, end, gran): None (datetime.datetime(2001, 2, 1, 0, 0), datetime.datetime(2001, 3, 1, 0, 0)) None (datetime.datetime(2001, 3, 1, 0, 0), datetime.datetime(2001, 4, 1, 0, 0)) - """ + """ # noqa: E501 if not maps: return None @@ -1631,7 +1665,8 @@ def leading_zero(value): if shortcut_identifier: where += ( "{br} LIKE '{si}\\_%' {esc} OR {br} LIKE '%\\_{si}' {esc} OR " - "{br} LIKE '{orig}\\_%' {esc} OR {br} LIKE '%\\_{orig}' {esc}".format( + "{br} LIKE '{orig}\\_%' {esc} OR " + "{br} LIKE '%\\_{orig}' {esc}".format( br="semantic_label", si=shortcut_identifier, orig=self.semantic_label.upper(), @@ -1674,7 +1709,9 @@ def _update_where_statement_by_spatial_extent( >>> import grass.script as gs >>> where = None >>> spatial_extent = gs.parse_command("g.region", flags="ug3") - >>> _update_where_statement_by_spatial_extent(where, spatial_extent, "overlaps") + >>> _update_where_statement_by_spatial_extent( + ... where, spatial_extent, "overlaps" + ... ) ((north > 0 AND south < 1 AND east > 0 AND west < 1)) """ @@ -1690,7 +1727,8 @@ def _update_where_statement_by_spatial_extent( self.msgr.error( _( "Invalid spatial relation <{}> requested." - "Only values 'overlaps', 'is_contained', and 'contains' are allowed." + "Only values 'overlaps', 'is_contained', and 'contains' are \ + allowed." ).format(spatial_relation) ) raise @@ -1857,14 +1895,16 @@ def shift_map_list(maps, gran): >>> import grass.temporal as tgis >>> maps = [] >>> for i in range(5): - ... map = tgis.RasterDataset(None) - ... if i%2 == 0: - ... check = map.set_relative_time(i, i + 1, 'years') - ... else: - ... check = map.set_relative_time(i, None, 'years') - ... maps.append(map) + ... map = tgis.RasterDataset(None) + ... if i % 2 == 0: + ... check = map.set_relative_time(i, i + 1, "years") + ... else: + ... check = map.set_relative_time(i, None, "years") + ... maps.append(map) + ... >>> for map in maps: - ... map.temporal_extent.print_info() + ... map.temporal_extent.print_info() + ... +-------------------- Relative time -----------------------------------------+ | Start time:................. 0 | End time:................... 1 @@ -1887,7 +1927,8 @@ def shift_map_list(maps, gran): | Relative time unit:......... years >>> maps = tgis.AbstractSpaceTimeDataset.shift_map_list(maps, 5) >>> for map in maps: - ... map.temporal_extent.print_info() + ... map.temporal_extent.print_info() + ... +-------------------- Relative time -----------------------------------------+ | Start time:................. 5 | End time:................... 6 @@ -1909,7 +1950,7 @@ def shift_map_list(maps, gran): | End time:................... 10 | Relative time unit:......... years - """ + """ # noqa: E501 if maps is None: return None @@ -2009,14 +2050,16 @@ def snap_map_list(maps): >>> import grass.temporal as tgis >>> maps = [] >>> for i in range(5): - ... map = tgis.RasterDataset(None) - ... if i%2 == 0: - ... check = map.set_relative_time(i, i + 1, 'years') - ... else: - ... check = map.set_relative_time(i, None, 'years') - ... maps.append(map) + ... map = tgis.RasterDataset(None) + ... if i % 2 == 0: + ... check = map.set_relative_time(i, i + 1, "years") + ... else: + ... check = map.set_relative_time(i, None, "years") + ... maps.append(map) + ... >>> for map in maps: - ... map.temporal_extent.print_info() + ... map.temporal_extent.print_info() + ... +-------------------- Relative time -----------------------------------------+ | Start time:................. 0 | End time:................... 1 @@ -2039,7 +2082,8 @@ def snap_map_list(maps): | Relative time unit:......... years >>> maps = tgis.AbstractSpaceTimeDataset.snap_map_list(maps) >>> for map in maps: - ... map.temporal_extent.print_info() + ... map.temporal_extent.print_info() + ... +-------------------- Relative time -----------------------------------------+ | Start time:................. 0 | End time:................... 1 @@ -2061,7 +2105,7 @@ def snap_map_list(maps): | End time:................... 5 | Relative time unit:......... years - """ + """ # noqa: E501 if maps is None or len(maps) == 0: return None diff --git a/python/grass/temporal/aggregation.py b/python/grass/temporal/aggregation.py index 22b2d772afb..223dcfa29f5 100644 --- a/python/grass/temporal/aggregation.py +++ b/python/grass/temporal/aggregation.py @@ -7,7 +7,9 @@ import grass.temporal as tgis - tgis.aggregate_raster_maps(dataset, mapset, inputs, base, start, end, count, method, register_null, dbif) + tgis.aggregate_raster_maps( + dataset, mapset, inputs, base, start, end, count, method, register_null, dbif + ) (C) 2012-2013 by the GRASS Development Team This program is free software under the GNU General Public diff --git a/python/grass/temporal/base.py b/python/grass/temporal/base.py index 1f2b6290aa6..d11f8a081ac 100644 --- a/python/grass/temporal/base.py +++ b/python/grass/temporal/base.py @@ -24,6 +24,7 @@ :author: Soeren Gebbert """ + from datetime import datetime from .core import ( get_tgis_message_interface, @@ -55,8 +56,8 @@ def serialize(self, type, table, where=None): >>> t.D["name"] = "soil" >>> t.D["mapset"] = "PERMANENT" >>> t.D["creator"] = "soeren" - >>> t.D["creation_time"] = datetime(2001,1,1) - >>> t.D["modification_time"] = datetime(2001,1,1) + >>> t.D["creation_time"] = datetime(2001, 1, 1) + >>> t.D["modification_time"] = datetime(2001, 1, 1) >>> t.serialize(type="SELECT", table="raster_base") ('SELECT name , creator , creation_time , modification_time , mapset , id FROM raster_base ;\\n', ()) >>> t.serialize(type="INSERT", table="raster_base") @@ -71,7 +72,7 @@ def serialize(self, type, table, where=None): :param where: The optional where statement :return: a tuple containing the SQL string and the arguments - """ + """ # noqa: E501 sql = "" args = [] @@ -218,7 +219,7 @@ class SQLDatabaseInterface(DictSQLSerializer): >>> t.D["name"] = "soil" >>> t.D["mapset"] = "PERMANENT" >>> t.D["creator"] = "soeren" - >>> t.D["creation_time"] = datetime(2001,1,1) + >>> t.D["creation_time"] = datetime(2001, 1, 1) >>> t.get_delete_statement() "DELETE FROM raster WHERE id = 'soil@PERMANENT';\\n" >>> t.get_is_in_db_statement() @@ -240,7 +241,7 @@ class SQLDatabaseInterface(DictSQLSerializer): >>> t.get_update_all_statement_mogrified() "UPDATE raster SET creation_time = '2001-01-01 00:00:00' ,mapset = 'PERMANENT' ,name = 'soil' ,creator = 'soeren' WHERE id = 'soil@PERMANENT';\\n" - """ + """ # noqa: E501 def __init__(self, table=None, ident=None): """Constructor of this class @@ -590,7 +591,13 @@ class DatasetBase(SQLDatabaseInterface): .. code-block:: python >>> init() - >>> t = DatasetBase("raster", "soil@PERMANENT", creator="soeren", ctime=datetime(2001,1,1), ttype="absolute") + >>> t = DatasetBase( + ... "raster", + ... "soil@PERMANENT", + ... creator="soeren", + ... ctime=datetime(2001, 1, 1), + ... ttype="absolute", + ... ) >>> t.id 'soil@PERMANENT' >>> t.name @@ -829,7 +836,7 @@ def print_info(self): """Print information about this class in human readable style""" # 0123456789012345678901234567890 print( - " +-------------------- Basic information -------------------------------------+" + " +-------------------- Basic information -------------------------------------+" # noqa: E501 ) print(" | Id: ........................ " + str(self.get_id())) print(" | Name: ...................... " + str(self.get_name())) @@ -954,7 +961,15 @@ class STDSBase(DatasetBase): .. code-block:: python >>> init() - >>> t = STDSBase("stds", "soil@PERMANENT", semantic_type="average", creator="soeren", ctime=datetime(2001,1,1), ttype="absolute", mtime=datetime(2001,1,1)) + >>> t = STDSBase( + ... "stds", + ... "soil@PERMANENT", + ... semantic_type="average", + ... creator="soeren", + ... ctime=datetime(2001, 1, 1), + ... ttype="absolute", + ... mtime=datetime(2001, 1, 1), + ... ) >>> t.semantic_type 'average' >>> t.print_info() diff --git a/python/grass/temporal/c_libraries_interface.py b/python/grass/temporal/c_libraries_interface.py index 4a908e49716..ab564df2312 100644 --- a/python/grass/temporal/c_libraries_interface.py +++ b/python/grass/temporal/c_libraries_interface.py @@ -51,6 +51,7 @@ class RPCDefs: WRITE_SEMANTIC_LABEL = 15 READ_SEMANTIC_LABEL = 16 REMOVE_SEMANTIC_LABEL = 17 + READ_MAP_HISTORY = 18 G_FATAL_ERROR = 49 TYPE_RASTER = 0 @@ -981,6 +982,142 @@ def _read_vector_info(name, mapset): ############################################################################### +def _read_map_history(lock, conn, data): + """Read map history from the spatial database using C-library functions + + :param lock: A multiprocessing.Lock instance + :param conn: A multiprocessing.Pipe instance used to send True or False + :param data: The list of data entries [function_id, maptype, name, mapset] + """ + kvp = None + try: + maptype = data[1] + name = data[2] + mapset = data[3] + if maptype == RPCDefs.TYPE_RASTER: + kvp = _read_raster_history(name, mapset) + elif maptype == RPCDefs.TYPE_VECTOR: + kvp = _read_vector_history(name, mapset) + elif maptype == RPCDefs.TYPE_RASTER3D: + kvp = _read_raster3d_history(name, mapset) + except: + raise + finally: + conn.send(kvp) + + +############################################################################### + + +def _read_raster_history(name, mapset): + """Read the raster history from the file system and store the content + into a dictionary + + This method uses the ctypes interface to the gis and raster libraries + to read the map history + + :param name: The name of the map + :param mapset: The mapset of the map + :returns: The key value pairs of the map specific metadata, or None in + case of an error + """ + + kvp = {} + + if not libgis.G_find_raster(name, mapset): + return None + + # Read the raster history + hist = libraster.History() + ret = libraster.Rast_read_history(name, mapset, byref(hist)) + if ret < 0: + logging.warning(_("Unable to read history file")) + return None + else: + kvp["creation_time"] = decode( + libraster.Rast_get_history(byref(hist), libraster.HIST_MAPID) + ) + kvp["creator"] = decode( + libraster.Rast_get_history(byref(hist), libraster.HIST_CREATOR) + ) + + return kvp + + +############################################################################### + + +def _read_raster3d_history(name, mapset): + """Read the 3D raster map info from the file system and store the content + into a dictionary + + This method uses the ctypes interface to the gis and raster3d libraries + to read the map metadata information + + :param name: The name of the map + :param mapset: The mapset of the map + :returns: The key value pairs of the map specific metadata, or None in + case of an error + """ + + kvp = {} + + if not libgis.G_find_raster3d(name, mapset): + return None + + # Read the region information + hist = libraster.History() + ret = libraster3d.Rast3d_read_history(name, mapset, byref(hist)) + if ret < 0: + logging.warning(_("Unable to read history file")) + return None + else: + kvp["creation_time"] = decode( + libraster.Rast_get_history(byref(hist), libraster3d.HIST_MAPID) + ) + kvp["creator"] = decode( + libraster.Rast_get_history(byref(hist), libraster3d.HIST_CREATOR) + ) + + return kvp + + +############################################################################### + + +def _read_vector_history(name, mapset): + """Read the vector history from the file system and store the content + into a dictionary + + This method uses the ctypes interface to the gis and raster libraries + to read the map history + + :param name: The name of the map + :param mapset: The mapset of the map + :returns: The key value pairs of the map specific metadata, or None in + case of an error + """ + + kvp = {} + + if not libgis.G_find_vector(name, mapset): + return None + + # Read the vector history + Map = libvector.Map_info() + if libvector.Vect_open_old(byref(Map), name, mapset, "1") > 0: + kvp["creation_time"] = decode(libvector.Vect_get_map_date(byref(Map))) + kvp["creator"] = decode(libvector.Vect_get_person(byref(Map))) + else: + None + libvector.Vect_close(byref(Map)) + + return kvp + + +############################################################################### + + def _convert_timestamp_from_grass(ts): """Convert a GRASS file based timestamp into the temporal framework format datetime or integer. @@ -1124,6 +1261,7 @@ def error_handler(data): functions[RPCDefs.WRITE_SEMANTIC_LABEL] = _write_semantic_label functions[RPCDefs.READ_SEMANTIC_LABEL] = _read_semantic_label functions[RPCDefs.REMOVE_SEMANTIC_LABEL] = _remove_semantic_label + functions[RPCDefs.READ_MAP_HISTORY] = _read_map_history functions[RPCDefs.G_FATAL_ERROR] = _fatal_error libgis.G_gisinit("c_library_server") @@ -1159,21 +1297,54 @@ class CLibrariesInterface(RPCServerBase): >>> import grass.script as gscript >>> import grass.temporal as tgis >>> gscript.use_temp_region() - >>> gscript.run_command("g.region", n=80.0, s=0.0, e=120.0, w=0.0, - ... t=1.0, b=0.0, res=10.0, res3=10.0) + >>> gscript.run_command( + ... "g.region", + ... n=80.0, + ... s=0.0, + ... e=120.0, + ... w=0.0, + ... t=1.0, + ... b=0.0, + ... res=10.0, + ... res3=10.0, + ... ) 0 >>> tgis.init() - >>> gscript.run_command("r.mapcalc", expression="test = 1", overwrite=True, quiet=True) + >>> gscript.run_command( + ... "r.mapcalc", expression="test = 1", overwrite=True, quiet=True + ... ) 0 - >>> gscript.run_command("r3.mapcalc", expression="test = 1", overwrite=True, quiet=True) + >>> gscript.run_command( + ... "r3.mapcalc", expression="test = 1", overwrite=True, quiet=True + ... ) 0 - >>> gscript.run_command("v.random", output="test", n=10, overwrite=True, quiet=True) + >>> gscript.run_command( + ... "v.random", output="test", n=10, overwrite=True, quiet=True + ... ) 0 - >>> gscript.run_command("r.timestamp", map="test", date='12 Mar 1995 10:34:40', overwrite=True, quiet=True) + >>> gscript.run_command( + ... "r.timestamp", + ... map="test", + ... date="12 Mar 1995 10:34:40", + ... overwrite=True, + ... quiet=True, + ... ) 0 - >>> gscript.run_command("r3.timestamp", map="test", date='12 Mar 1995 10:34:40', overwrite=True, quiet=True) + >>> gscript.run_command( + ... "r3.timestamp", + ... map="test", + ... date="12 Mar 1995 10:34:40", + ... overwrite=True, + ... quiet=True, + ... ) 0 - >>> gscript.run_command("v.timestamp", map="test", date='12 Mar 1995 10:34:40', overwrite=True, quiet=True) + >>> gscript.run_command( + ... "v.timestamp", + ... map="test", + ... date="12 Mar 1995 10:34:40", + ... overwrite=True, + ... quiet=True, + ... ) 0 # Check mapsets @@ -1185,13 +1356,13 @@ class CLibrariesInterface(RPCServerBase): # Raster map >>> ciface = tgis.CLibrariesInterface() >>> check = ciface.raster_map_exists("test", tgis.get_current_mapset()) - >>> print check + >>> print(check) True >>> ciface.read_raster_info("test", tgis.get_current_mapset()) {'rows': 12, 'north': 80.0, 'min': 1, 'datatype': 'CELL', 'max': 1, 'ewres': 10.0, 'cols': 8, 'west': 0.0, 'east': 120.0, 'nsres': 10.0, 'south': 0.0} >>> info = ciface.read_raster_full_info("test", tgis.get_current_mapset()) - >>> info # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE + >>> info # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE {u'tbres': 1.0, ... 'keyword': 'generated by r.mapcalc', u'bottom': 0.0, 'end_time': None, 'title': 'test', u'south': 0.0} @@ -1200,18 +1371,21 @@ class CLibrariesInterface(RPCServerBase): >>> info["end_time"] >>> check = ciface.has_raster_timestamp("test", tgis.get_current_mapset()) - >>> print check + >>> print(check) True >>> if check: ... res = ciface.read_raster_timestamp("test", tgis.get_current_mapset()) ... if res[0]: - ... print str(res[1][0]), str(res[1][0]) + ... print(str(res[1][0]), str(res[1][0])) ... ciface.remove_raster_timestamp("test", tgis.get_current_mapset()) + ... 1995-03-12 10:34:40 1995-03-12 10:34:40 1 >>> ciface.has_raster_timestamp("test", tgis.get_current_mapset()) False - >>> ciface.write_raster_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05") + >>> ciface.write_raster_timestamp( + ... "test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05" + ... ) 1 >>> ciface.has_raster_timestamp("test", tgis.get_current_mapset()) True @@ -1219,23 +1393,26 @@ class CLibrariesInterface(RPCServerBase): # 3D raster map >>> check = ciface.raster3d_map_exists("test", tgis.get_current_mapset()) - >>> print check + >>> print(check) True >>> ciface.read_raster3d_info("test", tgis.get_current_mapset()) {'tbres': 1.0, 'rows': 12, 'north': 80.0, 'bottom': 0.0, 'datatype': 'DCELL', 'max': 1.0, 'top': 1.0, 'min': 1.0, 'cols': 8, 'depths': 1, 'west': 0.0, 'ewres': 10.0, 'east': 120.0, 'nsres': 10.0, 'south': 0.0} >>> check = ciface.has_raster3d_timestamp("test", tgis.get_current_mapset()) - >>> print check + >>> print(check) True >>> if check: ... res = ciface.read_raster3d_timestamp("test", tgis.get_current_mapset()) ... if res[0]: - ... print str(res[1][0]), str(res[1][0]) + ... print(str(res[1][0]), str(res[1][0])) ... ciface.remove_raster3d_timestamp("test", tgis.get_current_mapset()) + ... 1995-03-12 10:34:40 1995-03-12 10:34:40 1 >>> ciface.has_raster3d_timestamp("test", tgis.get_current_mapset()) False - >>> ciface.write_raster3d_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05") + >>> ciface.write_raster3d_timestamp( + ... "test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05" + ... ) 1 >>> ciface.has_raster3d_timestamp("test", tgis.get_current_mapset()) True @@ -1243,42 +1420,45 @@ class CLibrariesInterface(RPCServerBase): # Vector map >>> check = ciface.vector_map_exists("test", tgis.get_current_mapset()) - >>> print check + >>> print(check) True >>> kvp = ciface.read_vector_info("test", tgis.get_current_mapset()) - >>> kvp['points'] + >>> kvp["points"] 10 >>> kvp = ciface.read_vector_full_info("test", tgis.get_current_mapset()) - >>> print kvp['points'] + >>> print(kvp["points"]) 10 - >>> kvp['point'] + >>> kvp["point"] 10 - >>> kvp['area'] + >>> kvp["area"] 0 - >>> kvp['lines'] + >>> kvp["lines"] 0 - >>> kvp['line'] + >>> kvp["line"] 0 - >>> 'columns' in kvp + >>> "columns" in kvp False >>> kvp["start_time"] datetime.datetime(1995, 3, 12, 10, 34, 40) >>> kvp["end_time"] >>> check = ciface.has_vector_timestamp("test", tgis.get_current_mapset(), None) - >>> print check + >>> print(check) True >>> if check: ... res = ciface.read_vector_timestamp("test", tgis.get_current_mapset()) ... if res[0]: - ... print str(res[1][0]), str(res[1][0]) + ... print(str(res[1][0]), str(res[1][0])) ... ciface.remove_vector_timestamp("test", tgis.get_current_mapset()) + ... 1995-03-12 10:34:40 1995-03-12 10:34:40 1 >>> ciface.has_vector_timestamp("test", tgis.get_current_mapset()) False - >>> ciface.write_vector_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05") + >>> ciface.write_vector_timestamp( + ... "test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05" + ... ) 1 >>> ciface.has_vector_timestamp("test", tgis.get_current_mapset()) True @@ -1292,22 +1472,22 @@ class CLibrariesInterface(RPCServerBase): >>> location = ciface.get_location() >>> gisdbase = ciface.get_gisdbase() - >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE Traceback (most recent call last): raise FatalError("Exception raised: " + str(e) + " Message: " + message) FatalError: Exception raised: ... - >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE Traceback (most recent call last): raise FatalError("Exception raised: " + str(e) + " Message: " + message) FatalError: Exception raised: ... - >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE Traceback (most recent call last): raise FatalError("Exception raised: " + str(e) + " Message: " + message) FatalError: Exception raised: ... - >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE Traceback (most recent call last): raise FatalError("Exception raised: " + str(e) + " Message: " + message) FatalError: Exception raised: ... @@ -1316,7 +1496,7 @@ class CLibrariesInterface(RPCServerBase): >>> gscript.del_temp_region() - """ + """ # noqa: E501 def __init__(self): RPCServerBase.__init__(self) @@ -1374,6 +1554,21 @@ def read_raster_full_info(self, name, mapset): ) return self.safe_receive("read_raster_full_info") + def read_raster_history(self, name, mapset): + """Read the raster map history from the file system and store the content + into a dictionary + + :param name: The name of the map + :param mapset: The mapset of the map + :returns: The key value pairs of the map history (creation, creation_time), + or None in case of an error + """ + self.check_server() + self.client_conn.send( + [RPCDefs.READ_MAP_HISTORY, RPCDefs.TYPE_RASTER, name, mapset, None] + ) + return self.safe_receive("read_raster_history") + def has_raster_timestamp(self, name, mapset): """Check if a file based raster timestamp exists @@ -1533,6 +1728,21 @@ def read_raster3d_info(self, name, mapset): ) return self.safe_receive("read_raster3d_info") + def read_raster3d_history(self, name, mapset): + """Read the 3D raster map history from the file system and store the content + into a dictionary + + :param name: The name of the map + :param mapset: The mapset of the map + :returns: The key value pairs of the map history (creation, creation_time), + or None in case of an error + """ + self.check_server() + self.client_conn.send( + [RPCDefs.READ_MAP_HISTORY, RPCDefs.TYPE_RASTER3D, name, mapset, None] + ) + return self.safe_receive("read_raster3d_history") + def has_raster3d_timestamp(self, name, mapset): """Check if a file based 3D raster timestamp exists @@ -1655,6 +1865,21 @@ def read_vector_full_info(self, name, mapset): ) return self.safe_receive("read_vector_full_info") + def read_vector_history(self, name, mapset): + """Read the vector map history from the file system and store the content + into a dictionary + + :param name: The name of the map + :param mapset: The mapset of the map + :returns: The key value pairs of the map history (creation, creation_time), + or None in case of an error + """ + self.check_server() + self.client_conn.send( + [RPCDefs.READ_MAP_HISTORY, RPCDefs.TYPE_VECTOR, name, mapset, None] + ) + return self.safe_receive("read_vector_history") + def has_vector_timestamp(self, name, mapset, layer=None): """Check if a file based vector timestamp exists diff --git a/python/grass/temporal/core.py b/python/grass/temporal/core.py index 4b7fe953b51..68db2716ae5 100644 --- a/python/grass/temporal/core.py +++ b/python/grass/temporal/core.py @@ -15,8 +15,9 @@ >>> # Execute a SQL statement >>> dbif.execute_transaction("SELECT datetime(0, 'unixepoch', 'localtime');") >>> # Mogrify an SQL statement - >>> dbif.mogrify_sql_statement(["SELECT name from raster_base where name = ?", - ... ("precipitation",)]) + >>> dbif.mogrify_sql_statement( + ... ["SELECT name from raster_base where name = ?", ("precipitation",)] + ... ) "SELECT name from raster_base where name = 'precipitation'" >>> dbif.close() @@ -28,6 +29,7 @@ :author: Soeren Gebbert """ + # import traceback import os import grass.script as gscript @@ -489,7 +491,8 @@ def get_available_temporal_mapsets(): ) if driver and database: # Check if the temporal sqlite database exists - # We need to set non-existing databases in case the mapset is the current mapset + # We need to set non-existing databases in case the mapset is the current + # mapset # to create it if ( driver == "sqlite" and os.path.exists(database) @@ -1393,8 +1396,14 @@ def mogrify_sql_statement(self, content): >>> init() >>> dbif = SQLDatabaseInterfaceConnection() - >>> dbif.mogrify_sql_statement(["SELECT ctime FROM raster_base WHERE id = ?", - ... ["soil@PERMANENT",]]) + >>> dbif.mogrify_sql_statement( + ... [ + ... "SELECT ctime FROM raster_base WHERE id = ?", + ... [ + ... "soil@PERMANENT", + ... ], + ... ] + ... ) "SELECT ctime FROM raster_base WHERE id = 'soil@PERMANENT'" """ @@ -1601,8 +1610,9 @@ def init_dbif(dbif): dbif, connection_state_changed = tgis.init_dbif(None) - sql = dbif.mogrify_sql_statement(["SELECT * FROM raster_base WHERE ? = ?"], - ["id", "soil@PERMANENT"]) + sql = dbif.mogrify_sql_statement( + ["SELECT * FROM raster_base WHERE ? = ?"], ["id", "soil@PERMANENT"] + ) dbif.execute_transaction(sql) if connection_state_changed: diff --git a/python/grass/temporal/datetime_math.py b/python/grass/temporal/datetime_math.py index 66bee770ead..29bcc8907de 100644 --- a/python/grass/temporal/datetime_math.py +++ b/python/grass/temporal/datetime_math.py @@ -8,6 +8,7 @@ :authors: Soeren Gebbert """ + from datetime import datetime, timedelta from .core import get_tgis_message_interface import copy @@ -156,7 +157,9 @@ def increment_datetime_by_string(mydate, increment, mult=1): .. code-block:: python >>> dt = datetime(2001, 9, 1, 0, 0, 0) - >>> string = "60 seconds, 4 minutes, 12 hours, 10 days, 1 weeks, 5 months, 1 years" + >>> string = ( + ... "60 seconds, 4 minutes, 12 hours, 10 days, 1 weeks, 5 months, 1 years" + ... ) >>> increment_datetime_by_string(dt, string) datetime.datetime(2003, 2, 18, 12, 5) @@ -388,7 +391,7 @@ def adjust_datetime_to_granularity(mydate, granularity): .. code-block:: python - >>> dt = datetime(2001, 8, 8, 12,30,30) + >>> dt = datetime(2001, 8, 8, 12, 30, 30) >>> adjust_datetime_to_granularity(dt, "5 seconds") datetime.datetime(2001, 8, 8, 12, 30, 30) @@ -413,7 +416,9 @@ def adjust_datetime_to_granularity(mydate, granularity): >>> adjust_datetime_to_granularity(dt, "2 years") datetime.datetime(2001, 1, 1, 0, 0) - >>> adjust_datetime_to_granularity(dt, "2 years, 3 months, 5 days, 3 hours, 3 minutes, 2 seconds") + >>> adjust_datetime_to_granularity( + ... dt, "2 years, 3 months, 5 days, 3 hours, 3 minutes, 2 seconds" + ... ) datetime.datetime(2001, 8, 8, 12, 30, 30) >>> adjust_datetime_to_granularity(dt, "3 months, 5 days, 3 minutes") @@ -520,129 +525,129 @@ def compute_datetime_delta(start, end): .. code-block:: python - >>> start = datetime(2001, 1, 1, 00,00,00) - >>> end = datetime(2001, 1, 1, 00,00,00) + >>> start = datetime(2001, 1, 1, 0, 0, 0) + >>> end = datetime(2001, 1, 1, 0, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 0, 'month': 0, 'second': 0, 'max_days': 0, 'year': 0, 'day': 0, 'minute': 0} - >>> start = datetime(2001, 1, 1, 00,00,14) - >>> end = datetime(2001, 1, 1, 00,00,44) + >>> start = datetime(2001, 1, 1, 0, 0, 14) + >>> end = datetime(2001, 1, 1, 0, 0, 44) >>> compute_datetime_delta(start, end) {'hour': 0, 'month': 0, 'second': 30, 'max_days': 0, 'year': 0, 'day': 0, 'minute': 0} - >>> start = datetime(2001, 1, 1, 00,00,44) - >>> end = datetime(2001, 1, 1, 00,01,14) + >>> start = datetime(2001, 1, 1, 0, 0, 44) + >>> end = datetime(2001, 1, 1, 0, 1, 14) >>> compute_datetime_delta(start, end) {'hour': 0, 'month': 0, 'second': 30, 'max_days': 0, 'year': 0, 'day': 0, 'minute': 1} - >>> start = datetime(2001, 1, 1, 00,00,30) - >>> end = datetime(2001, 1, 1, 00,05,30) + >>> start = datetime(2001, 1, 1, 0, 0, 30) + >>> end = datetime(2001, 1, 1, 0, 5, 30) >>> compute_datetime_delta(start, end) {'hour': 0, 'month': 0, 'second': 300, 'max_days': 0, 'year': 0, 'day': 0, 'minute': 5} - >>> start = datetime(2001, 1, 1, 00,00,00) - >>> end = datetime(2001, 1, 1, 00,01,00) + >>> start = datetime(2001, 1, 1, 0, 0, 0) + >>> end = datetime(2001, 1, 1, 0, 1, 0) >>> compute_datetime_delta(start, end) {'hour': 0, 'month': 0, 'second': 0, 'max_days': 0, 'year': 0, 'day': 0, 'minute': 1} - >>> start = datetime(2011,10,31, 00,45,00) - >>> end = datetime(2011,10,31, 01,45,00) + >>> start = datetime(2011, 10, 31, 0, 45, 0) + >>> end = datetime(2011, 10, 31, 1, 45, 0) >>> compute_datetime_delta(start, end) {'hour': 1, 'second': 0, 'max_days': 0, 'year': 0, 'day': 0, 'minute': 60} - >>> start = datetime(2011,10,31, 00,45,00) - >>> end = datetime(2011,10,31, 01,15,00) + >>> start = datetime(2011, 10, 31, 0, 45, 0) + >>> end = datetime(2011, 10, 31, 1, 15, 0) >>> compute_datetime_delta(start, end) {'hour': 1, 'second': 0, 'max_days': 0, 'year': 0, 'day': 0, 'minute': 30} - >>> start = datetime(2011,10,31, 00,45,00) - >>> end = datetime(2011,10,31, 12,15,00) + >>> start = datetime(2011, 10, 31, 0, 45, 0) + >>> end = datetime(2011, 10, 31, 12, 15, 0) >>> compute_datetime_delta(start, end) {'hour': 12, 'second': 0, 'max_days': 0, 'year': 0, 'day': 0, 'minute': 690} - >>> start = datetime(2011,10,31, 00,00,00) - >>> end = datetime(2011,10,31, 01,00,00) + >>> start = datetime(2011, 10, 31, 0, 0, 0) + >>> end = datetime(2011, 10, 31, 1, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 1, 'second': 0, 'max_days': 0, 'year': 0, 'day': 0, 'minute': 0} - >>> start = datetime(2011,10,31, 00,00,00) - >>> end = datetime(2011,11,01, 01,00,00) + >>> start = datetime(2011, 10, 31, 0, 0, 0) + >>> end = datetime(2011, 11, 1, 1, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 25, 'second': 0, 'max_days': 1, 'year': 0, 'day': 1, 'minute': 0} - >>> start = datetime(2011,10,31, 12,00,00) - >>> end = datetime(2011,11,01, 06,00,00) + >>> start = datetime(2011, 10, 31, 12, 0, 0) + >>> end = datetime(2011, 11, 1, 6, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 18, 'second': 0, 'max_days': 0, 'year': 0, 'day': 0, 'minute': 0} - >>> start = datetime(2011,11,01, 00,00,00) - >>> end = datetime(2011,12,01, 01,00,00) + >>> start = datetime(2011, 11, 1, 0, 0, 0) + >>> end = datetime(2011, 12, 1, 1, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 721, 'month': 1, 'second': 0, 'max_days': 30, 'year': 0, 'day': 0, 'minute': 0} - >>> start = datetime(2011,11,01, 00,00,00) - >>> end = datetime(2011,11,05, 00,00,00) + >>> start = datetime(2011, 11, 1, 0, 0, 0) + >>> end = datetime(2011, 11, 5, 0, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 0, 'second': 0, 'max_days': 4, 'year': 0, 'day': 4, 'minute': 0} - >>> start = datetime(2011,10,06, 00,00,00) - >>> end = datetime(2011,11,05, 00,00,00) + >>> start = datetime(2011, 10, 6, 0, 0, 0) + >>> end = datetime(2011, 11, 5, 0, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 0, 'second': 0, 'max_days': 30, 'year': 0, 'day': 30, 'minute': 0} - >>> start = datetime(2011,12,02, 00,00,00) - >>> end = datetime(2012,01,01, 00,00,00) + >>> start = datetime(2011, 12, 2, 0, 0, 0) + >>> end = datetime(2012, 1, 1, 0, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 0, 'second': 0, 'max_days': 30, 'year': 1, 'day': 30, 'minute': 0} - >>> start = datetime(2011,01,01, 00,00,00) - >>> end = datetime(2011,02,01, 00,00,00) + >>> start = datetime(2011, 1, 1, 0, 0, 0) + >>> end = datetime(2011, 2, 1, 0, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 0, 'month': 1, 'second': 0, 'max_days': 31, 'year': 0, 'day': 0, 'minute': 0} - >>> start = datetime(2011,12,01, 00,00,00) - >>> end = datetime(2012,01,01, 00,00,00) + >>> start = datetime(2011, 12, 1, 0, 0, 0) + >>> end = datetime(2012, 1, 1, 0, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 0, 'month': 1, 'second': 0, 'max_days': 31, 'year': 1, 'day': 0, 'minute': 0} - >>> start = datetime(2011,12,01, 00,00,00) - >>> end = datetime(2012,06,01, 00,00,00) + >>> start = datetime(2011, 12, 1, 0, 0, 0) + >>> end = datetime(2012, 6, 1, 0, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 0, 'month': 6, 'second': 0, 'max_days': 183, 'year': 1, 'day': 0, 'minute': 0} - >>> start = datetime(2011,06,01, 00,00,00) - >>> end = datetime(2021,06,01, 00,00,00) + >>> start = datetime(2011, 6, 1, 0, 0, 0) + >>> end = datetime(2021, 6, 1, 0, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 0, 'month': 120, 'second': 0, 'max_days': 3653, 'year': 10, 'day': 0, 'minute': 0} - >>> start = datetime(2011,06,01, 00,00,00) - >>> end = datetime(2012,06,01, 12,00,00) + >>> start = datetime(2011, 6, 1, 0, 0, 0) + >>> end = datetime(2012, 6, 1, 12, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 8796, 'month': 12, 'second': 0, 'max_days': 366, 'year': 1, 'day': 0, 'minute': 0} - >>> start = datetime(2011,06,01, 00,00,00) - >>> end = datetime(2012,06,01, 12,30,00) + >>> start = datetime(2011, 6, 1, 0, 0, 0) + >>> end = datetime(2012, 6, 1, 12, 30, 0) >>> compute_datetime_delta(start, end) {'hour': 8796, 'month': 12, 'second': 0, 'max_days': 366, 'year': 1, 'day': 0, 'minute': 527790} - >>> start = datetime(2011,06,01, 00,00,00) - >>> end = datetime(2012,06,01, 12,00,05) + >>> start = datetime(2011, 6, 1, 0, 0, 0) + >>> end = datetime(2012, 6, 1, 12, 0, 5) >>> compute_datetime_delta(start, end) {'hour': 8796, 'month': 12, 'second': 31665605, 'max_days': 366, 'year': 1, 'day': 0, 'minute': 0} - >>> start = datetime(2011,06,01, 00,00,00) - >>> end = datetime(2012,06,01, 00,30,00) + >>> start = datetime(2011, 6, 1, 0, 0, 0) + >>> end = datetime(2012, 6, 1, 0, 30, 0) >>> compute_datetime_delta(start, end) {'hour': 0, 'month': 12, 'second': 0, 'max_days': 366, 'year': 1, 'day': 0, 'minute': 527070} - >>> start = datetime(2011,06,01, 00,00,00) - >>> end = datetime(2012,06,01, 00,00,05) + >>> start = datetime(2011, 12, 1, 0, 0, 0) + >>> end = datetime(2012, 6, 1, 0, 0, 0) >>> compute_datetime_delta(start, end) {'hour': 0, 'month': 12, 'second': 31622405, 'max_days': 366, 'year': 1, 'day': 0, 'minute': 0} :return: A dictionary with year, month, day, hour, minute and second as keys() - """ + """ # noqa: E501 comp = {} day_diff = (end - start).days @@ -992,7 +997,8 @@ def create_numeric_suffix(base, count, zeros): :param base: the basename for new map :param count: a number - :param zeros: a string containing the expected number, coming from suffix option like "%05" + :param zeros: a string containing the expected number, coming from suffix option + like "%05" """ spli = zeros.split("%") if len(spli) == 2: diff --git a/python/grass/temporal/extract.py b/python/grass/temporal/extract.py index 9cb91ac2230..3f8c9cb0738 100644 --- a/python/grass/temporal/extract.py +++ b/python/grass/temporal/extract.py @@ -8,6 +8,7 @@ :authors: Soeren Gebbert """ + from .core import ( get_tgis_message_interface, get_current_mapset, diff --git a/python/grass/temporal/factory.py b/python/grass/temporal/factory.py index cc3652ff4ca..b7ef8ab5218 100644 --- a/python/grass/temporal/factory.py +++ b/python/grass/temporal/factory.py @@ -17,6 +17,7 @@ :authors: Soeren Gebbert """ + from .core import get_tgis_message_interface from .space_time_datasets import ( SpaceTimeRaster3DDataset, diff --git a/python/grass/temporal/gui_support.py b/python/grass/temporal/gui_support.py index 44e32b6e2e8..09b858657bc 100644 --- a/python/grass/temporal/gui_support.py +++ b/python/grass/temporal/gui_support.py @@ -9,6 +9,7 @@ :authors: Soeren Gebbert """ + from .core import get_available_temporal_mapsets, init_dbif from .factory import dataset_factory import grass.script as gscript diff --git a/python/grass/temporal/list_stds.py b/python/grass/temporal/list_stds.py index 785bb9217f6..e913409fd60 100644 --- a/python/grass/temporal/list_stds.py +++ b/python/grass/temporal/list_stds.py @@ -60,21 +60,37 @@ def get_dataset_list( >>> import grass.temporal as tgis >>> tgis.core.init() >>> name = "list_stds_test" - >>> sp = tgis.open_stds.open_new_stds(name=name, type="strds", - ... temporaltype="absolute", title="title", descr="descr", - ... semantic="mean", dbif=None, overwrite=True) + >>> sp = tgis.open_stds.open_new_stds( + ... name=name, + ... type="strds", + ... temporaltype="absolute", + ... title="title", + ... descr="descr", + ... semantic="mean", + ... dbif=None, + ... overwrite=True, + ... ) >>> mapset = tgis.get_current_mapset() - >>> stds_list = tgis.list_stds.get_dataset_list("strds", "absolute", columns="name") - >>> rows = stds_list[mapset] + >>> stds_list = tgis.list_stds.get_dataset_list( + ... "strds", "absolute", columns="name" + ... ) + >>> rows = stds_list[mapset] >>> for row in rows: ... if row["name"] == name: ... print(True) + ... True - >>> stds_list = tgis.list_stds.get_dataset_list("strds", "absolute", columns="name,mapset", where="mapset = '%s'"%(mapset)) - >>> rows = stds_list[mapset] + >>> stds_list = tgis.list_stds.get_dataset_list( + ... "strds", + ... "absolute", + ... columns="name,mapset", + ... where="mapset = '%s'" % (mapset), + ... ) + >>> rows = stds_list[mapset] >>> for row in rows: ... if row["name"] == name and row["mapset"] == mapset: ... print(True) + ... True >>> check = sp.delete() @@ -249,7 +265,8 @@ def _write_table(rows, column_names, output_format, separator, file): elif output_format == "yaml": _write_yaml(rows=rows, column_names=column_names, file=file) elif output_format == "plain": - # No particular reason for this separator expect that this is the original behavior. + # No particular reason for this separator except that this is the original + # behavior. if not separator: separator = "\t" _write_plain(rows=rows, header=column_names, separator=separator, file=file) @@ -443,11 +460,14 @@ def check_columns(column_names, output_format, element_type): ).format( name=dataset.get_id(), element_type=element_type, - detail=_( - "Dataset is empty or where clause is too constrained or incorrect" - ) - if where - else _("Dataset is empty"), + detail=( + _( + "Dataset is empty or where clause is too constrained or " + "incorrect" + ) + if where + else _("Dataset is empty") + ), ) ) if connection_state_changed: diff --git a/python/grass/temporal/mapcalc.py b/python/grass/temporal/mapcalc.py index e23d8cac165..54edeab885d 100644 --- a/python/grass/temporal/mapcalc.py +++ b/python/grass/temporal/mapcalc.py @@ -8,6 +8,7 @@ :authors: Soeren Gebbert """ + import copy from datetime import datetime from multiprocessing import Process diff --git a/python/grass/temporal/metadata.py b/python/grass/temporal/metadata.py index b9bd7adcc41..6094bbbe146 100644 --- a/python/grass/temporal/metadata.py +++ b/python/grass/temporal/metadata.py @@ -21,6 +21,7 @@ :authors: Soeren Gebbert """ + from .base import SQLDatabaseInterface from .core import SQLDatabaseInterfaceConnection, get_tgis_db_version_from_metadata @@ -35,9 +36,18 @@ class RasterMetadataBase(SQLDatabaseInterface): .. code-block:: python >>> init() - >>> meta = RasterMetadataBase(table="metadata", ident="soil@PERMANENT", - ... datatype="CELL", cols=100, rows=100, number_of_cells=10000, nsres=0.1, - ... ewres=0.1, min=0, max=100) + >>> meta = RasterMetadataBase( + ... table="metadata", + ... ident="soil@PERMANENT", + ... datatype="CELL", + ... cols=100, + ... rows=100, + ... number_of_cells=10000, + ... nsres=0.1, + ... ewres=0.1, + ... min=0, + ... max=100, + ... ) >>> meta.datatype 'CELL' >>> meta.cols @@ -284,9 +294,17 @@ class RasterMetadata(RasterMetadataBase): .. code-block:: python >>> init() - >>> meta = RasterMetadata(ident="soil@PERMANENT", - ... datatype="CELL", cols=100, rows=100, number_of_cells=10000, nsres=0.1, - ... ewres=0.1, min=0, max=100) + >>> meta = RasterMetadata( + ... ident="soil@PERMANENT", + ... datatype="CELL", + ... cols=100, + ... rows=100, + ... number_of_cells=10000, + ... nsres=0.1, + ... ewres=0.1, + ... min=0, + ... max=100, + ... ) >>> meta.datatype 'CELL' >>> meta.cols @@ -398,10 +416,19 @@ class Raster3DMetadata(RasterMetadataBase): .. code-block:: python >>> init() - >>> meta = Raster3DMetadata(ident="soil@PERMANENT", - ... datatype="FCELL", cols=100, rows=100, depths=100, - ... number_of_cells=1000000, nsres=0.1, ewres=0.1, tbres=0.1, - ... min=0, max=100) + >>> meta = Raster3DMetadata( + ... ident="soil@PERMANENT", + ... datatype="FCELL", + ... cols=100, + ... rows=100, + ... depths=100, + ... number_of_cells=1000000, + ... nsres=0.1, + ... ewres=0.1, + ... tbres=0.1, + ... min=0, + ... max=100, + ... ) >>> meta.datatype 'FCELL' >>> meta.cols @@ -541,11 +568,22 @@ class VectorMetadata(SQLDatabaseInterface): .. code-block:: python >>> init() - >>> meta = VectorMetadata(ident="lidar@PERMANENT", is_3d=True, - ... number_of_points=1, number_of_lines=2, number_of_boundaries=3, - ... number_of_centroids=4, number_of_faces=5, number_of_kernels=6, - ... number_of_primitives=7, number_of_nodes=8, number_of_areas=9, - ... number_of_islands=10, number_of_holes=11, number_of_volumes=12) + >>> meta = VectorMetadata( + ... ident="lidar@PERMANENT", + ... is_3d=True, + ... number_of_points=1, + ... number_of_lines=2, + ... number_of_boundaries=3, + ... number_of_centroids=4, + ... number_of_faces=5, + ... number_of_kernels=6, + ... number_of_primitives=7, + ... number_of_nodes=8, + ... number_of_areas=9, + ... number_of_islands=10, + ... number_of_holes=11, + ... number_of_volumes=12, + ... ) >>> meta.id 'lidar@PERMANENT' >>> meta.is_3d @@ -894,8 +932,9 @@ class STDSMetadataBase(SQLDatabaseInterface): .. code-block:: python >>> init() - >>> meta = STDSMetadataBase(ident="soils@PERMANENT", - ... title="Soils", description="Soils 1950 - 2010") + >>> meta = STDSMetadataBase( + ... ident="soils@PERMANENT", title="Soils", description="Soils 1950 - 2010" + ... ) >>> meta.id 'soils@PERMANENT' >>> meta.title @@ -1014,7 +1053,7 @@ def _print_info_head(self, shell=False): """ if not shell: print( - " +-------------------- Metadata information ----------------------------------+" + " +-------------------- Metadata information ----------------------------------+" # noqa: E501 ) def _print_info_tail(self, shell=False): @@ -1085,8 +1124,9 @@ class for strds and str3ds datasets .. code-block:: python >>> init() - >>> meta = STDSRasterMetadataBase(ident="soils@PERMANENT", - ... title="Soils", description="Soils 1950 - 2010") + >>> meta = STDSRasterMetadataBase( + ... ident="soils@PERMANENT", title="Soils", description="Soils 1950 - 2010" + ... ) >>> meta.id 'soils@PERMANENT' >>> meta.title @@ -1303,8 +1343,9 @@ class STRDSMetadata(STDSRasterMetadataBase): .. code-block:: python >>> init() - >>> meta = STRDSMetadata(ident="soils@PERMANENT", - ... title="Soils", description="Soils 1950 - 2010") + >>> meta = STRDSMetadata( + ... ident="soils@PERMANENT", title="Soils", description="Soils 1950 - 2010" + ... ) >>> meta.id 'soils@PERMANENT' >>> meta.title @@ -1477,8 +1518,9 @@ class STR3DSMetadata(STDSRasterMetadataBase): .. code-block:: python >>> init() - >>> meta = STR3DSMetadata(ident="soils@PERMANENT", - ... title="Soils", description="Soils 1950 - 2010") + >>> meta = STR3DSMetadata( + ... ident="soils@PERMANENT", title="Soils", description="Soils 1950 - 2010" + ... ) >>> meta.id 'soils@PERMANENT' >>> meta.title @@ -1619,8 +1661,11 @@ class STVDSMetadata(STDSMetadataBase): .. code-block:: python >>> init() - >>> meta = STVDSMetadata(ident="lidars@PERMANENT", - ... title="LIDARS", description="LIDARS 2008 - 2010") + >>> meta = STVDSMetadata( + ... ident="lidars@PERMANENT", + ... title="LIDARS", + ... description="LIDARS 2008 - 2010", + ... ) >>> meta.id 'lidars@PERMANENT' >>> meta.title diff --git a/python/grass/temporal/open_stds.py b/python/grass/temporal/open_stds.py index 837f1a860a7..83aacc1c819 100644 --- a/python/grass/temporal/open_stds.py +++ b/python/grass/temporal/open_stds.py @@ -17,6 +17,7 @@ :authors: Soeren Gebbert """ + from .core import init_dbif, get_current_mapset, get_tgis_message_interface from .factory import dataset_factory from .abstract_map_dataset import AbstractMapDataset diff --git a/python/grass/temporal/register.py b/python/grass/temporal/register.py index 7514cb33d03..149a304f628 100644 --- a/python/grass/temporal/register.py +++ b/python/grass/temporal/register.py @@ -16,8 +16,9 @@ :authors: Soeren Gebbert """ + from datetime import datetime -import grass.script as gscript +import grass.script as gs from .core import get_tgis_message_interface, init_dbif, get_current_mapset from .open_stds import open_old_stds from .abstract_map_dataset import AbstractMapDataset @@ -81,6 +82,7 @@ def register_maps_in_space_time_dataset( start_time_in_file = False end_time_in_file = False semantic_label_in_file = False + overwrite = gs.overwrite() msgr = get_tgis_message_interface() @@ -95,15 +97,13 @@ def register_maps_in_space_time_dataset( increment = str(increment) if maps and file: - msgr.fatal(_("%s= and %s= are mutually exclusive") % ("maps", "file")) + msgr.fatal(_("maps and file are mutually exclusive")) if end and increment: - msgr.fatal(_("%s= and %s= are mutually exclusive") % ("end", "increment")) + msgr.fatal(_("end and increment are mutually exclusive")) if end and interval: - msgr.fatal( - _("%s= and the %s flag are mutually exclusive") % ("end", "interval") - ) + msgr.fatal(_("end and the interval flag are mutually exclusive")) if increment and not start: msgr.fatal(_("The increment option requires the start option")) @@ -112,13 +112,14 @@ def register_maps_in_space_time_dataset( msgr.fatal(_("The interval flag requires the start option")) if end and not start: - msgr.fatal(_("Please specify %s= and %s=") % ("start_time", "end_time")) + msgr.fatal(_("Please specify start_time and end_time")) if not maps and not file: - msgr.fatal(_("Please specify %s= or %s=") % ("maps", "file")) + msgr.fatal(_("Please specify maps or file")) + # We may need the mapset mapset = get_current_mapset() - dbif, connection_state_changed = init_dbif(None) + dbif, connection_state_changed = init_dbif(dbif) # create new stds only in the current mapset # remove all connections to any other mapsets @@ -135,23 +136,17 @@ def register_maps_in_space_time_dataset( dbif.close() msgr.fatal( _( - "Space time %(sp)s dataset <%(name)s> with relative" - " time found, but no relative unit set for %(sp)s " + "Space time {sp} dataset <{name}> with relative" + " time found, but no relative unit set for {sp} " "maps" - ) - % {"name": name, "sp": sp.get_new_map_instance(None).get_type()} + ).format(name=name, sp=sp.get_new_map_instance(None).get_type()) ) maplist = [] # Map names as comma separated string if maps: - if maps.find(",") < 0: - maplist = [ - maps, - ] - else: - maplist = maps.split(",") + maplist = maps.split(",") # Build the map list again with the ids for idx, maplist_item in enumerate(maplist): @@ -220,7 +215,8 @@ def register_maps_in_space_time_dataset( increment = None msgr.warning( _( - "The increment option will be ignored because of time stamps in input file" + "The increment option will be ignored because of time stamps in " + "input file" ) ) @@ -228,7 +224,8 @@ def register_maps_in_space_time_dataset( increment = None msgr.warning( _( - "The interval flag will be ignored because of time stamps in input file" + "The interval flag will be ignored because of time stamps in input " + "file" ) ) fd.close() @@ -241,155 +238,148 @@ def register_maps_in_space_time_dataset( msgr.debug(2, "Gathering map information...") - for count in range(len(maplist)): + for count, row in enumerate(maplist): if count % 50 == 0: msgr.percent(count, num_maps, 1) # Get a new instance of the map type - map = dataset_factory(type, maplist[count]["id"]) + map_object = dataset_factory(type, row["id"]) - if map.map_exists() is not True: + map_object_id = map_object.get_map_id() + map_object_layer = map_object.get_layer() + map_object_type = map_object.get_type() + if not map_object.map_exists(): msgr.fatal( - _("Unable to update %(t)s map <%(id)s>. " "The map does not exist.") - % {"t": map.get_type(), "id": map.get_map_id()} + _("Unable to update {t} map <{mid}>. The map does not exist.").format( + t=map_object_type, mid=map_object_id + ) ) # Use the time data from file - if "start" in maplist[count]: - start = maplist[count]["start"] - if "end" in maplist[count]: - end = maplist[count]["end"] + if "start" in row: + start = row["start"] + if "end" in row: + end = row["end"] # Use the semantic label from file - if "semantic_label" in maplist[count]: - semantic_label = maplist[count]["semantic_label"] + if "semantic_label" in row: + semantic_label = row["semantic_label"] else: semantic_label = None - is_in_db = False + is_in_db = map_object.is_in_db(dbif, mapset) # Put the map into the database of the current mapset - if not map.is_in_db(dbif, mapset): + if not is_in_db: # Break in case no valid time is provided - if (start == "" or start is None) and not map.has_grass_timestamp(): + if (start == "" or start is None) and not map_object.has_grass_timestamp(): dbif.close() - if map.get_layer(): + if map_object_layer: msgr.fatal( _( - "Unable to register %(t)s map <%(id)s> with " - "layer %(l)s. The map has timestamp and " + "Unable to register {t} map <{mid}> with " + "layer {l}. The map has timestamp and " "the start time is not set." + ).format( + t=map_object_type, + mid=map_object_id, + l=map_object_layer, ) - % { - "t": map.get_type(), - "id": map.get_map_id(), - "l": map.get_layer(), - } ) else: msgr.fatal( _( - "Unable to register %(t)s map <%(id)s>. The" + "Unable to register {t} map <{mid}>. The" " map has no timestamp and the start time " "is not set." - ) - % {"t": map.get_type(), "id": map.get_map_id()} + ).format(t=map_object_type, mid=map_object_id) ) if start != "" and start is not None: # We need to check if the time is absolute and the unit was specified time_object = check_datetime_string(start) if isinstance(time_object, datetime) and unit: - msgr.fatal( - _("%(u)s= can only be set for relative time") % {"u": "unit"} - ) + msgr.fatal(_("unit can only be set for relative time")) if not isinstance(time_object, datetime) and not unit: - msgr.fatal( - _("%(u)s= must be set in case of relative time" " stamps") - % {"u": "unit"} - ) + msgr.fatal(_("unit must be set in case of relative time stamps")) if unit: - map.set_time_to_relative() + map_object.set_time_to_relative() else: - map.set_time_to_absolute() + map_object.set_time_to_absolute() else: - is_in_db = True # Check the overwrite flag - if not gscript.overwrite(): - if map.get_layer(): + if not overwrite: + if map_object_layer: msgr.warning( _( "Map is already registered in temporal " - "database. Unable to update %(t)s map " - "<%(id)s> with layer %(l)s. Overwrite flag" + "database. Unable to update {t} map " + "<{mid}> with layer {l}. Overwrite flag" " is not set." + ).format( + t=map_object_type, + mid=map_object_id, + l=str(map_object_layer), ) - % { - "t": map.get_type(), - "id": map.get_map_id(), - "l": str(map.get_layer()), - } ) else: msgr.warning( _( "Map is already registered in temporal " - "database. Unable to update %(t)s map " - "<%(id)s>. Overwrite flag is not set." - ) - % {"t": map.get_type(), "id": map.get_map_id()} + "database. Unable to update {t} map " + "<{mid}>. Overwrite flag is not set." + ).format(t=map_object_type, mid=map_object_id) ) # Simple registration is allowed if name: - map_object_list.append(map) + map_object_list.append(map_object) # Jump to next map continue - # Select information from temporal database - map.select(dbif) + # Reload properties from database + map_object.select(dbif) # Save the datasets that must be updated - datasets = map.get_registered_stds(dbif) + datasets = map_object.get_registered_stds(dbif) if datasets is not None: for dataset in datasets: if dataset != "": datatsets_to_modify[dataset] = dataset - if name and map.get_temporal_type() != sp.get_temporal_type(): + if name and map_object.get_temporal_type() != sp.get_temporal_type(): dbif.close() - if map.get_layer(): + if map_object_layer: msgr.fatal( _( - "Unable to update %(t)s map <%(id)s> " - "with layer %(l)s. The temporal types " + "Unable to update {t} map <{id}> " + "with layer {l}. The temporal types " "are different." + ).format( + t=map_object_type, + mid=map_object_id, + l=map_object_layer, ) - % { - "t": map.get_type(), - "id": map.get_map_id(), - "l": map.get_layer(), - } ) else: msgr.fatal( _( - "Unable to update %(t)s map <%(id)s>. " + "Unable to update {t} map <{mid}>. " "The temporal types are different." - ) - % {"t": map.get_type(), "id": map.get_map_id()} + ).format(t=map_object_type, mid=map_object_id) ) # Load the data from the grass file database - map.load() + map_object.load() # Try to read an existing time stamp from the grass spatial database # in case this map wasn't already registered in the temporal database - # Read the spatial database time stamp only, if no time stamp was provided for this map + # Read the spatial database time stamp only, if no time stamp was provided for + # this map # as method argument or in the input file if not is_in_db and not start: - map.read_timestamp_from_grass() + map_object.read_timestamp_from_grass() # Set the valid time if start: @@ -398,8 +388,8 @@ def register_maps_in_space_time_dataset( if start_time_in_file: count = 1 assign_valid_time_to_map( - ttype=map.get_temporal_type(), - map=map, + ttype=map_object.get_temporal_type(), + map_object=map_object, start=start, end=end, unit=unit, @@ -413,17 +403,17 @@ def register_maps_in_space_time_dataset( # semantic label defined in input file # -> update raster metadata # -> write band identifier to GRASS data base - map.set_semantic_label(semantic_label) + map_object.set_semantic_label(semantic_label) else: # Try to read semantic label from GRASS data base if defined - map.read_semantic_label_from_grass() + map_object.read_semantic_label_from_grass() if is_in_db: # Gather the SQL update statement - statement += map.update_all(dbif=dbif, execute=False) + statement += map_object.update_all(dbif=dbif, execute=False) else: # Gather the SQL insert statement - statement += map.insert(dbif=dbif, execute=False) + statement += map_object.insert(dbif=dbif, execute=False) # Sqlite3 performance is better for huge datasets when committing in # small chunks @@ -435,7 +425,7 @@ def register_maps_in_space_time_dataset( # Store the maps in a list to register in a space time dataset if name: - map_object_list.append(map) + map_object_list.append(map_object) msgr.percent(num_maps, num_maps, 1) @@ -444,13 +434,11 @@ def register_maps_in_space_time_dataset( # Finally Register the maps in the space time dataset if name and map_object_list: - count = 0 num_maps = len(map_object_list) - for map in map_object_list: + for count, map_object in enumerate(map_object_list): if count % 50 == 0: msgr.percent(count, num_maps, 1) - sp.register_map(map=map, dbif=dbif) - count += 1 + sp.register_map(map=map_object, dbif=dbif) # Update the space time tables if name and map_object_list: @@ -461,11 +449,11 @@ def register_maps_in_space_time_dataset( # Update affected datasets if datatsets_to_modify: for dataset in datatsets_to_modify: - if type == "rast" or type == "raster": + if type in ["rast", "raster"]: ds = dataset_factory("strds", dataset) - elif type == "raster_3d" or type == "rast3d" or type == "raster3d": + elif type in ["raster_3d", "rast3d", "raster3d"]: ds = dataset_factory("str3ds", dataset) - elif type == "vect" or type == "vector": + elif type in ["vect", "vector"]: ds = dataset_factory("stvds", dataset) ds.select(dbif) ds.update_from_registered_maps(dbif) @@ -480,7 +468,7 @@ def register_maps_in_space_time_dataset( def assign_valid_time_to_map( - ttype, map, start, end, unit, increment=None, mult=1, interval=False + ttype, map_object, start, end, unit, increment=None, mult=1, interval=False ): """Assign the valid time to a map dataset @@ -509,7 +497,7 @@ def assign_valid_time_to_map( start_time = string_to_datetime(start) if start_time is None: msgr.fatal( - _('Unable to convert string "%s"into a ' "datetime object") % (start) + _('Unable to convert string "{}" into a datetime object').format(start) ) end_time = None @@ -517,7 +505,9 @@ def assign_valid_time_to_map( end_time = string_to_datetime(end) if end_time is None: msgr.fatal( - _('Unable to convert string "%s"into a ' "datetime object") % (end) + _('Unable to convert string "{}" into a datetime object').format( + end + ) ) # Add the increment @@ -530,28 +520,33 @@ def assign_valid_time_to_map( if end_time is None: msgr.fatal(_("Error occurred in increment computation")) - if map.get_layer(): + if map_object.get_layer(): msgr.debug( 1, _( - "Set absolute valid time for map <%(id)s> with " - "layer %(layer)s to %(start)s - %(end)s" - ) - % { - "id": map.get_map_id(), - "layer": map.get_layer(), - "start": str(start_time), - "end": str(end_time), - }, + "Set absolute valid time for map <{id}> with " + "layer {layer} to {start} - {end}" + ).format( + id=map_object.get_map_id(), + layer=map_object.get_layer(), + start=str(start_time), + end=str(end_time), + ), ) else: msgr.debug( 1, - _("Set absolute valid time for map <%s> to %s - %s") - % (map.get_map_id(), str(start_time), str(end_time)), + _( + "Set absolute valid time for map <{mid}> to " + "{start_time} - {end_time}" + ).format( + mid=map_object.get_map_id(), + start_time=str(start_time), + end_time=str(end_time), + ), ) - map.set_absolute_time(start_time, end_time) + map_object.set_absolute_time(start_time, end_time) else: start_time = int(start) end_time = None @@ -564,23 +559,35 @@ def assign_valid_time_to_map( if interval: end_time = start_time + int(increment) - if map.get_layer(): + if map_object.get_layer(): msgr.debug( 1, _( - "Set relative valid time for map <%s> with layer" - " %s to %i - %s with unit %s" - ) - % (map.get_map_id(), map.get_layer(), start_time, str(end_time), unit), + "Set relative valid time for map <{mid}> with layer" + " {layer} to {start} - {end} with unit {unit}" + ).format( + mid=map_object.get_map_id(), + layer=map_object.get_layer(), + start=start_time, + end=str(end_time), + unit=unit, + ), ) else: msgr.debug( 1, - _("Set relative valid time for map <%s> to %i - %s " "with unit %s") - % (map.get_map_id(), start_time, str(end_time), unit), + _( + "Set relative valid time for map <{mid}> to " + "{start} - {end} with unit {unit}" + ).format( + mid=map_object.get_map_id(), + start=start_time, + end=str(end_time), + unit=unit, + ), ) - map.set_relative_time(start_time, end_time, unit) + map_object.set_relative_time(start_time, end_time, unit) ############################################################################## @@ -603,37 +610,34 @@ def register_map_object_list( import grass.pygrass.modules as pymod import copy - dbif, connection_state_changed = init_dbif(dbif) + dbif, connection_state_changed = init_dbif(None) - filename = gscript.tempfile(True) - file = open(filename, "w") - - empty_maps = [] - for map_layer in map_list: - # Read the map data - map_layer.load() - # In case of a empty map continue, do not register empty maps - - if delete_empty: - if type in ["raster", "raster_3d", "rast", "rast3d"]: - if ( - map_layer.metadata.get_min() is None - and map_layer.metadata.get_max() is None - ): - empty_maps.append(map_layer) - continue - if type == "vector": - if map_layer.metadata.get_number_of_primitives() == 0: - empty_maps.append(map_layer) - continue - - start, end = map_layer.get_temporal_extent_as_tuple() - id = map_layer.get_id() - if not end: - end = start - string = "%s|%s|%s\n" % (id, str(start), str(end)) - file.write(string) - file.close() + filename = gs.tempfile(True) + with open(filename, "w") as register_file: + empty_maps = [] + for map_layer in map_list: + # Read the map data + map_layer.load() + # In case of a empty map continue, do not register empty maps + if delete_empty: + if type in ["raster", "raster_3d", "rast", "rast3d"]: + if ( + map_layer.metadata.get_min() is None + and map_layer.metadata.get_max() is None + ): + empty_maps.append(map_layer) + continue + if type == "vector": + if map_layer.metadata.get_number_of_primitives() == 0: + empty_maps.append(map_layer) + continue + + start, end = map_layer.get_temporal_extent_as_tuple() + id = map_layer.get_id() + if not end: + end = start + string = f"{id}|{start}|{end}\n" + register_file.write(string) if output_stds: output_stds_id = output_stds.get_id() @@ -644,22 +648,21 @@ def register_map_object_list( type, output_stds_id, unit=unit, file=filename, dbif=dbif ) - g_remove = pymod.Module("g.remove", flags="f", quiet=True, run_=False, finish_=True) - # Remove empty maps and unregister them from the temporal database + g_remove = pymod.Module("g.remove", flags="f", quiet=True, run_=False, finish_=True) if len(empty_maps) > 0: - for map in empty_maps: + for map_object in empty_maps: mod = copy.deepcopy(g_remove) - if map.get_name(): - if map.get_type() == "raster": - mod(type="raster", name=map.get_name()) - if map.get_type() == "raster3d": - mod(type="raster_3d", name=map.get_name()) - if map.get_type() == "vector": - mod(type="vector", name=map.get_name()) + if map_object.get_name(): + if map_object.get_type() == "raster": + mod(type="raster", name=map_object.get_name()) + if map_object.get_type() == "raster3d": + mod(type="raster_3d", name=map_object.get_name()) + if map_object.get_type() == "vector": + mod(type="vector", name=map_object.get_name()) mod.run() - if map.is_in_db(dbif): - map.delete(dbif) + if map_object.is_in_db(dbif): + map_object.delete(dbif) if connection_state_changed: dbif.close() diff --git a/python/grass/temporal/sampling.py b/python/grass/temporal/sampling.py index 38fdd1aed53..afe84ce57b3 100644 --- a/python/grass/temporal/sampling.py +++ b/python/grass/temporal/sampling.py @@ -16,6 +16,7 @@ :authors: Soeren Gebbert """ + from .core import ( get_current_mapset, get_tgis_message_interface, diff --git a/python/grass/temporal/space_time_datasets.py b/python/grass/temporal/space_time_datasets.py index df1da106e0c..a32cb2d2fac 100644 --- a/python/grass/temporal/space_time_datasets.py +++ b/python/grass/temporal/space_time_datasets.py @@ -8,7 +8,9 @@ :authors: Soeren Gebbert """ + import getpass +from datetime import datetime from .abstract_map_dataset import AbstractMapDataset from .abstract_space_time_dataset import AbstractSpaceTimeDataset from .base import ( @@ -55,6 +57,8 @@ import grass.script.array as garray +GRASS_TIMESTAMP_FMT = "%a %b %d %H:%M:%S %Y" + ############################################################################### @@ -72,14 +76,20 @@ class RasterDataset(AbstractMapDataset): >>> import grass.temporal as tgis >>> init() >>> gs.use_temp_region() - >>> gs.run_command("g.region", n=80.0, s=0.0, e=120.0, w=0.0, - ... t=1.0, b=0.0, res=10.0) + >>> gs.run_command( + ... "g.region", n=80.0, s=0.0, e=120.0, w=0.0, t=1.0, b=0.0, res=10.0 + ... ) 0 - >>> gs.run_command("r.mapcalc", overwrite=True, quiet=True, - ... expression="strds_map_test_case = 1") + >>> gs.run_command( + ... "r.mapcalc", + ... overwrite=True, + ... quiet=True, + ... expression="strds_map_test_case = 1", + ... ) 0 - >>> gs.run_command("r.timestamp", map="strds_map_test_case", - ... date="15 jan 1999", quiet=True) + >>> gs.run_command( + ... "r.timestamp", map="strds_map_test_case", date="15 jan 1999", quiet=True + ... ) 0 >>> mapset = tgis.get_current_mapset() >>> name = "strds_map_test_case" @@ -116,8 +126,9 @@ class RasterDataset(AbstractMapDataset): | Minimum value:.............. 1.0 | Maximum value:.............. 1.0 - >>> gs.run_command("r.timestamp", map="strds_map_test_case", - ... date="2 years", quiet=True) + >>> gs.run_command( + ... "r.timestamp", map="strds_map_test_case", date="2 years", quiet=True + ... ) 0 >>> rmap.read_timestamp_from_grass() True @@ -138,8 +149,9 @@ class RasterDataset(AbstractMapDataset): True >>> rmap.get_type() 'raster' - >>> rmap.set_absolute_time(start_time=datetime(2001,1,1), - ... end_time=datetime(2012,1,1)) + >>> rmap.set_absolute_time( + ... start_time=datetime(2001, 1, 1), end_time=datetime(2012, 1, 1) + ... ) True >>> rmap.get_absolute_time() (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 0, 0)) @@ -225,7 +237,7 @@ def get_np_array(self): """Return this raster map as memmap numpy style array to access the raster values in numpy style without loading the whole map in the RAM. - In case this raster map does exists in the grass spatial database, + In case this raster map does exist in the grass spatial database, the map will be exported using r.out.bin to a temporary location and assigned to the memmap object that is returned by this function. @@ -259,7 +271,7 @@ def has_grass_timestamp(self): def read_timestamp_from_grass(self): """Read the timestamp of this map from the map metadata in the grass file system based spatial database and - set the internal time stamp that should be insert/updated + set the internal time stamp that should be inserted/updated in the temporal database. :return: True if success, False on error @@ -346,7 +358,7 @@ def remove_timestamp_from_grass(self): def read_semantic_label_from_grass(self): """Read the semantic label of this map from the map metadata in the GRASS file system based spatial database and - set the internal semantic label that should be insert/updated + set the internal semantic label that should be inserted/updated in the temporal database. :return: True if success, False if semantic labels could not be @@ -408,7 +420,16 @@ def load(self): return False # Fill base information - self.base.set_creator(str(getpass.getuser())) + kvp = self.ciface.read_raster_history(self.get_name(), self.get_mapset()) + + if kvp: + self.base.set_creator(kvp["creator"]) + self.base.set_ctime( + datetime.strptime(kvp["creation_time"], GRASS_TIMESTAMP_FMT) + ) + else: + self.base.set_creator(str(getpass.getuser())) + self.base.set_ctime() kvp = self.ciface.read_raster_info(self.get_name(), self.get_mapset()) @@ -478,14 +499,31 @@ class Raster3DDataset(AbstractMapDataset): >>> import grass.script as gs >>> init() >>> gs.use_temp_region() - >>> gs.run_command("g.region", n=80.0, s=0.0, e=120.0, w=0.0, - ... t=100.0, b=0.0, res=10.0, res3=10.0) + >>> gs.run_command( + ... "g.region", + ... n=80.0, + ... s=0.0, + ... e=120.0, + ... w=0.0, + ... t=100.0, + ... b=0.0, + ... res=10.0, + ... res3=10.0, + ... ) 0 - >>> gs.run_command("r3.mapcalc", overwrite=True, quiet=True, - ... expression="str3ds_map_test_case = 1") + >>> gs.run_command( + ... "r3.mapcalc", + ... overwrite=True, + ... quiet=True, + ... expression="str3ds_map_test_case = 1", + ... ) 0 - >>> gs.run_command("r3.timestamp", map="str3ds_map_test_case", - ... date="15 jan 1999", quiet=True) + >>> gs.run_command( + ... "r3.timestamp", + ... map="str3ds_map_test_case", + ... date="15 jan 1999", + ... quiet=True, + ... ) 0 >>> mapset = get_current_mapset() >>> name = "str3ds_map_test_case" @@ -524,8 +562,9 @@ class Raster3DDataset(AbstractMapDataset): | Number of depths:........... 10 | Top-Bottom resolution:...... 10.0 - >>> gs.run_command("r3.timestamp", map="str3ds_map_test_case", - ... date="2 years", quiet=True) + >>> gs.run_command( + ... "r3.timestamp", map="str3ds_map_test_case", date="2 years", quiet=True + ... ) 0 >>> r3map.read_timestamp_from_grass() True @@ -546,8 +585,9 @@ class Raster3DDataset(AbstractMapDataset): True >>> r3map.get_type() 'raster3d' - >>> r3map.set_absolute_time(start_time=datetime(2001,1,1), - ... end_time=datetime(2012,1,1)) + >>> r3map.set_absolute_time( + ... start_time=datetime(2001, 1, 1), end_time=datetime(2012, 1, 1) + ... ) True >>> r3map.get_absolute_time() (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 0, 0)) @@ -565,7 +605,9 @@ class Raster3DDataset(AbstractMapDataset): True >>> r3map.is_time_relative() False - >>> gs.run_command("g.remove", flags="f", type="raster_3d", name=name, quiet=True) + >>> gs.run_command( + ... "g.remove", flags="f", type="raster_3d", name=name, quiet=True + ... ) 0 >>> gs.del_temp_region() @@ -648,7 +690,7 @@ def get_np_array(self): 3D raster values in numpy style without loading the whole map in the RAM. - In case this 3D raster map does exists in the grass spatial database, + In case this 3D raster map does exist in the grass spatial database, the map will be exported using r3.out.bin to a temporary location and assigned to the memmap object that is returned by this function. @@ -682,7 +724,7 @@ def has_grass_timestamp(self): def read_timestamp_from_grass(self): """Read the timestamp of this map from the map metadata in the grass file system based spatial database and - set the internal time stamp that should be insert/updated + set the internal time stamp that should be inserted/updated in the temporal database. :return: True if success, False on error @@ -790,7 +832,16 @@ def load(self): return False # Fill base information - self.base.set_creator(str(getpass.getuser())) + kvp = self.ciface.read_raster3d_history(self.get_name(), self.get_mapset()) + + if kvp: + self.base.set_creator(kvp["creator"]) + self.base.set_ctime( + datetime.strptime(kvp["creation_time"], GRASS_TIMESTAMP_FMT) + ) + else: + self.base.set_creator(str(getpass.getuser())) + self.base.set_ctime() # Fill spatial extent kvp = self.ciface.read_raster3d_info(self.get_name(), self.get_mapset()) @@ -845,14 +896,25 @@ class VectorDataset(AbstractMapDataset): >>> import grass.script as gs >>> init() >>> gs.use_temp_region() - >>> gs.run_command("g.region", n=80.0, s=0.0, e=120.0, w=0.0, - ... t=1.0, b=0.0, res=10.0) + >>> gs.run_command( + ... "g.region", n=80.0, s=0.0, e=120.0, w=0.0, t=1.0, b=0.0, res=10.0 + ... ) 0 - >>> gs.run_command("v.random", overwrite=True, output="stvds_map_test_case", - ... n=100, zmin=0, zmax=100, flags="z", column="elevation", quiet=True) + >>> gs.run_command( + ... "v.random", + ... overwrite=True, + ... output="stvds_map_test_case", + ... n=100, + ... zmin=0, + ... zmax=100, + ... flags="z", + ... column="elevation", + ... quiet=True, + ... ) 0 - >>> gs.run_command("v.timestamp", map="stvds_map_test_case", - ... date="15 jan 1999", quiet=True) + >>> gs.run_command( + ... "v.timestamp", map="stvds_map_test_case", date="15 jan 1999", quiet=True + ... ) 0 >>> mapset = get_current_mapset() >>> name = "stvds_map_test_case" @@ -886,8 +948,9 @@ class VectorDataset(AbstractMapDataset): | Number of holes ............ 0 | Number of volumes .......... 0 - >>> gs.run_command("v.timestamp", map="stvds_map_test_case", - ... date="2 years", quiet=True) + >>> gs.run_command( + ... "v.timestamp", map="stvds_map_test_case", date="2 years", quiet=True + ... ) 0 >>> vmap.read_timestamp_from_grass() True @@ -908,8 +971,9 @@ class VectorDataset(AbstractMapDataset): True >>> vmap.get_type() 'vector' - >>> vmap.set_absolute_time(start_time=datetime(2001,1,1), - ... end_time=datetime(2012,1,1)) + >>> vmap.set_absolute_time( + ... start_time=datetime(2001, 1, 1), end_time=datetime(2012, 1, 1) + ... ) True >>> vmap.get_absolute_time() (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2012, 1, 1, 0, 0)) @@ -1012,7 +1076,7 @@ def has_grass_timestamp(self): def read_timestamp_from_grass(self): """Read the timestamp of this map from the map metadata in the grass file system based spatial database and - set the internal time stamp that should be insert/updated + set the internal time stamp that should be inserted/updated in the temporal database. """ @@ -1114,10 +1178,18 @@ def load(self): return False # Fill base information - self.base.set_creator(str(getpass.getuser())) + kvp = self.ciface.read_vector_history(self.get_name(), self.get_mapset()) - # Get the data from an existing vector map + if kvp: + self.base.set_creator(kvp["creator"]) + self.base.set_ctime( + datetime.strptime(kvp["creation_time"], GRASS_TIMESTAMP_FMT) + ) + else: + self.base.set_creator(str(getpass.getuser())) + self.base.set_ctime() + # Get the data from an existing vector map kvp = self.ciface.read_vector_info(self.get_name(), self.get_mapset()) if kvp: @@ -1162,20 +1234,20 @@ class SpaceTimeRasterDataset(AbstractSpaceTimeDataset): >>> import grass.temporal as tgis >>> tgis.init() >>> mapset = tgis.get_current_mapset() - >>> strds = tgis.SpaceTimeRasterDataset("old@%s"%mapset) + >>> strds = tgis.SpaceTimeRasterDataset("old@%s" % mapset) >>> strds.is_in_db() False >>> strds.is_stds() True >>> strds.get_type() 'strds' - >>> newstrds = strds.get_new_instance("newstrds@%s"%mapset) + >>> newstrds = strds.get_new_instance("newstrds@%s" % mapset) >>> isinstance(newstrds, SpaceTimeRasterDataset) True - >>> newmap = strds.get_new_map_instance("newmap@%s"%mapset) + >>> newmap = strds.get_new_map_instance("newmap@%s" % mapset) >>> isinstance(newmap, RasterDataset) True - >>> strds.reset("new@%s"%mapset) + >>> strds.reset("new@%s" % mapset) >>> strds.is_in_db() False >>> strds.reset(None) @@ -1278,20 +1350,20 @@ class SpaceTimeRaster3DDataset(AbstractSpaceTimeDataset): >>> import grass.temporal as tgis >>> tgis.init() >>> mapset = tgis.get_current_mapset() - >>> str3ds = tgis.SpaceTimeRaster3DDataset("old@%s"%mapset) + >>> str3ds = tgis.SpaceTimeRaster3DDataset("old@%s" % mapset) >>> str3ds.is_in_db() False >>> str3ds.is_stds() True >>> str3ds.get_type() 'str3ds' - >>> newstrds = str3ds.get_new_instance("newstrds@%s"%mapset) + >>> newstrds = str3ds.get_new_instance("newstrds@%s" % mapset) >>> isinstance(newstrds, SpaceTimeRaster3DDataset) True - >>> newmap = str3ds.get_new_map_instance("newmap@%s"%mapset) + >>> newmap = str3ds.get_new_map_instance("newmap@%s" % mapset) >>> isinstance(newmap, Raster3DDataset) True - >>> str3ds.reset("new@%s"%mapset) + >>> str3ds.reset("new@%s" % mapset) >>> str3ds.is_in_db() False >>> str3ds.reset(None) @@ -1404,20 +1476,20 @@ class SpaceTimeVectorDataset(AbstractSpaceTimeDataset): >>> import grass.temporal as tgis >>> tgis.init() >>> mapset = tgis.get_current_mapset() - >>> stvds = tgis.SpaceTimeVectorDataset("old@%s"%mapset) + >>> stvds = tgis.SpaceTimeVectorDataset("old@%s" % mapset) >>> stvds.is_in_db() False >>> stvds.is_stds() True >>> stvds.get_type() 'stvds' - >>> newstvds = stvds.get_new_instance("newstvds@%s"%mapset) + >>> newstvds = stvds.get_new_instance("newstvds@%s" % mapset) >>> isinstance(newstvds, SpaceTimeVectorDataset) True - >>> newmap = stvds.get_new_map_instance("newmap@%s"%mapset) + >>> newmap = stvds.get_new_map_instance("newmap@%s" % mapset) >>> isinstance(newmap, VectorDataset) True - >>> stvds.reset("new@%s"%mapset) + >>> stvds.reset("new@%s" % mapset) >>> stvds.is_in_db() False >>> stvds.reset(None) diff --git a/python/grass/temporal/spatial_extent.py b/python/grass/temporal/spatial_extent.py index 4288b7eadc6..7e026cf76eb 100644 --- a/python/grass/temporal/spatial_extent.py +++ b/python/grass/temporal/spatial_extent.py @@ -8,23 +8,59 @@ >>> import grass.temporal as tgis >>> tgis.init() >>> extent = tgis.RasterSpatialExtent( - ... ident="raster@PERMANENT", north=90, south=90, east=180, west=180, - ... top=100, bottom=-20) + ... ident="raster@PERMANENT", + ... north=90, + ... south=90, + ... east=180, + ... west=180, + ... top=100, + ... bottom=-20, + ... ) >>> extent = tgis.Raster3DSpatialExtent( - ... ident="raster3d@PERMANENT", north=90, south=90, east=180, west=180, - ... top=100, bottom=-20) + ... ident="raster3d@PERMANENT", + ... north=90, + ... south=90, + ... east=180, + ... west=180, + ... top=100, + ... bottom=-20, + ... ) >>> extent = tgis.VectorSpatialExtent( - ... ident="vector@PERMANENT", north=90, south=90, east=180, west=180, - ... top=100, bottom=-20) + ... ident="vector@PERMANENT", + ... north=90, + ... south=90, + ... east=180, + ... west=180, + ... top=100, + ... bottom=-20, + ... ) >>> extent = tgis.STRDSSpatialExtent( - ... ident="strds@PERMANENT", north=90, south=90, east=180, west=180, - ... top=100, bottom=-20) + ... ident="strds@PERMANENT", + ... north=90, + ... south=90, + ... east=180, + ... west=180, + ... top=100, + ... bottom=-20, + ... ) >>> extent = tgis.STR3DSSpatialExtent( - ... ident="str3ds@PERMANENT", north=90, south=90, east=180, west=180, - ... top=100, bottom=-20) + ... ident="str3ds@PERMANENT", + ... north=90, + ... south=90, + ... east=180, + ... west=180, + ... top=100, + ... bottom=-20, + ... ) >>> extent = tgis.STVDSSpatialExtent( - ... ident="stvds@PERMANENT", north=90, south=90, east=180, west=180, - ... top=100, bottom=-20) + ... ident="stvds@PERMANENT", + ... north=90, + ... south=90, + ... east=180, + ... west=180, + ... top=100, + ... bottom=-20, + ... ) (C) 2012-2013 by the GRASS Development Team This program is free software under the GNU General Public @@ -33,6 +69,7 @@ :authors: Soeren Gebbert """ + from .base import SQLDatabaseInterface @@ -47,9 +84,16 @@ class SpatialExtent(SQLDatabaseInterface): .. code-block:: python >>> init() - >>> extent = SpatialExtent(table="raster_spatial_extent", - ... ident="soil@PERMANENT", north=90, south=90, east=180, west=180, - ... top=100, bottom=-20) + >>> extent = SpatialExtent( + ... table="raster_spatial_extent", + ... ident="soil@PERMANENT", + ... north=90, + ... south=90, + ... east=180, + ... west=180, + ... top=100, + ... bottom=-20, + ... ) >>> extent.id 'soil@PERMANENT' >>> extent.north @@ -177,8 +221,12 @@ def overlapping(self, extent): .. code-block:: python - >>> A = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50) - >>> B = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) >>> A.overlapping(B) True @@ -265,10 +313,12 @@ def intersect(self, extent): .. code-block:: python - >>> A = SpatialExtent(north=80, south=20, east=60, west=10, - ... bottom=-50, top=50) - >>> B = SpatialExtent(north=80, south=20, east=60, west=10, - ... bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) >>> C = A.intersect(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ @@ -278,8 +328,9 @@ def intersect(self, extent): | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 - >>> B = SpatialExtent(north=40, south=30, east=60, west=10, - ... bottom=-50, top=50) + >>> B = SpatialExtent( + ... north=40, south=30, east=60, west=10, bottom=-50, top=50 + ... ) >>> C = A.intersect(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ @@ -289,8 +340,9 @@ def intersect(self, extent): | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 - >>> B = SpatialExtent(north=40, south=30, east=60, west=30, - ... bottom=-50, top=50) + >>> B = SpatialExtent( + ... north=40, south=30, east=60, west=30, bottom=-50, top=50 + ... ) >>> C = A.intersect(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ @@ -300,8 +352,9 @@ def intersect(self, extent): | West:....................... 30.0 | Top:........................ 50.0 | Bottom:..................... -50.0 - >>> B = SpatialExtent(north=40, south=30, east=60, west=30, - ... bottom=-30, top=50) + >>> B = SpatialExtent( + ... north=40, south=30, east=60, west=30, bottom=-30, top=50 + ... ) >>> C = A.intersect(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ @@ -311,8 +364,9 @@ def intersect(self, extent): | West:....................... 30.0 | Top:........................ 50.0 | Bottom:..................... -30.0 - >>> B = SpatialExtent(north=40, south=30, east=60, west=30, - ... bottom=-30, top=30) + >>> B = SpatialExtent( + ... north=40, south=30, east=60, west=30, bottom=-30, top=30 + ... ) >>> C = A.intersect(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ @@ -326,7 +380,7 @@ def intersect(self, extent): :param extent: The spatial extent to intersect with :return: The intersection spatial extent - """ + """ # noqa: E501 if not self.overlapping(extent): return None @@ -435,10 +489,12 @@ def disjoint_union(self, extent): .. code-block:: python - >>> A = SpatialExtent(north=80, south=20, east=60, west=10, - ... bottom=-50, top=50) - >>> B = SpatialExtent(north=80, south=20, east=60, west=10, - ... bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) >>> C = A.disjoint_union(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ @@ -448,8 +504,9 @@ def disjoint_union(self, extent): | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 - >>> B = SpatialExtent(north=40, south=30, east=60, west=10, - ... bottom=-50, top=50) + >>> B = SpatialExtent( + ... north=40, south=30, east=60, west=10, bottom=-50, top=50 + ... ) >>> C = A.disjoint_union(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ @@ -459,8 +516,9 @@ def disjoint_union(self, extent): | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 - >>> B = SpatialExtent(north=40, south=30, east=60, west=30, - ... bottom=-50, top=50) + >>> B = SpatialExtent( + ... north=40, south=30, east=60, west=30, bottom=-50, top=50 + ... ) >>> C = A.disjoint_union(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ @@ -470,8 +528,9 @@ def disjoint_union(self, extent): | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 - >>> B = SpatialExtent(north=40, south=30, east=60, west=30, - ... bottom=-30, top=50) + >>> B = SpatialExtent( + ... north=40, south=30, east=60, west=30, bottom=-30, top=50 + ... ) >>> C = A.disjoint_union(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ @@ -481,8 +540,9 @@ def disjoint_union(self, extent): | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 - >>> B = SpatialExtent(north=40, south=30, east=60, west=30, - ... bottom=-30, top=30) + >>> B = SpatialExtent( + ... north=40, south=30, east=60, west=30, bottom=-30, top=30 + ... ) >>> C = A.disjoint_union(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ @@ -492,10 +552,12 @@ def disjoint_union(self, extent): | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 - >>> A = SpatialExtent(north=80, south=20, east=60, west=10, - ... bottom=-50, top=50) - >>> B = SpatialExtent(north=90, south=80, east=70, west=20, - ... bottom=-30, top=60) + >>> A = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=90, south=80, east=70, west=20, bottom=-30, top=60 + ... ) >>> C = A.disjoint_union(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ @@ -509,7 +571,7 @@ def disjoint_union(self, extent): :param extent: The spatial extent to create a disjoint union with :return: The union spatial extent - """ + """ # noqa: E501 new = self.disjoint_union_2d(extent) @@ -595,10 +657,12 @@ def is_in(self, extent): .. code-block:: python - >>> A = SpatialExtent(north=79, south=21, east=59, west=11, - ... bottom=-49, top=49) - >>> B = SpatialExtent(north=80, south=20, east=60, west=10, - ... bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=79, south=21, east=59, west=11, bottom=-49, top=49 + ... ) + >>> B = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) >>> A.is_in(B) True >>> B.is_in(A) @@ -651,10 +715,12 @@ def contain(self, extent): .. code-block:: python - >>> A = SpatialExtent(north=80, south=20, east=60, west=10, - ... bottom=-50, top=50) - >>> B = SpatialExtent(north=79, south=21, east=59, west=11, - ... bottom=-49, top=49) + >>> A = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=79, south=21, east=59, west=11, bottom=-49, top=49 + ... ) >>> A.contain(B) True >>> B.contain(A) @@ -731,10 +797,12 @@ def equivalent(self, extent): .. code-block:: python - >>> A = SpatialExtent(north=80, south=20, east=60, west=10, - ... bottom=-50, top=50) - >>> B = SpatialExtent(north=80, south=20, east=60, west=10, - ... bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) >>> A.equivalent(B) True >>> B.equivalent(A) @@ -1413,18 +1481,26 @@ def spatial_relation(self, extent): .. code-block:: python - >>> A = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50) - >>> B = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) >>> A.spatial_relation(B) 'equivalent' >>> B.spatial_relation(A) 'equivalent' - >>> B = SpatialExtent(north=70, south=20, east=60, west=10, bottom=-50, top=50) + >>> B = SpatialExtent( + ... north=70, south=20, east=60, west=10, bottom=-50, top=50 + ... ) >>> A.spatial_relation_2d(B) 'cover' >>> A.spatial_relation(B) 'cover' - >>> B = SpatialExtent(north=70, south=30, east=60, west=10, bottom=-50, top=50) + >>> B = SpatialExtent( + ... north=70, south=30, east=60, west=10, bottom=-50, top=50 + ... ) >>> A.spatial_relation_2d(B) 'cover' >>> A.spatial_relation(B) @@ -1433,141 +1509,243 @@ def spatial_relation(self, extent): 'covered' >>> B.spatial_relation(A) 'covered' - >>> B = SpatialExtent(north=70, south=30, east=50, west=10, bottom=-50, top=50) + >>> B = SpatialExtent( + ... north=70, south=30, east=50, west=10, bottom=-50, top=50 + ... ) >>> A.spatial_relation_2d(B) 'cover' >>> B.spatial_relation_2d(A) 'covered' >>> A.spatial_relation(B) 'cover' - >>> B = SpatialExtent(north=70, south=30, east=50, west=20, bottom=-50, top=50) + >>> B = SpatialExtent( + ... north=70, south=30, east=50, west=20, bottom=-50, top=50 + ... ) >>> B.spatial_relation(A) 'covered' - >>> B = SpatialExtent(north=70, south=30, east=50, west=20, bottom=-50, top=50) + >>> B = SpatialExtent( + ... north=70, south=30, east=50, west=20, bottom=-50, top=50 + ... ) >>> A.spatial_relation_2d(B) 'contain' >>> A.spatial_relation(B) 'cover' - >>> B = SpatialExtent(north=70, south=30, east=50, west=20, bottom=-40, top=50) + >>> B = SpatialExtent( + ... north=70, south=30, east=50, west=20, bottom=-40, top=50 + ... ) >>> A.spatial_relation(B) 'cover' - >>> B = SpatialExtent(north=70, south=30, east=50, west=20, bottom=-40, top=40) + >>> B = SpatialExtent( + ... north=70, south=30, east=50, west=20, bottom=-40, top=40 + ... ) >>> A.spatial_relation(B) 'contain' >>> B.spatial_relation(A) 'in' - >>> B = SpatialExtent(north=90, south=30, east=50, west=20, bottom=-40, top=40) + >>> B = SpatialExtent( + ... north=90, south=30, east=50, west=20, bottom=-40, top=40 + ... ) >>> A.spatial_relation_2d(B) 'overlap' >>> A.spatial_relation(B) 'overlap' - >>> B = SpatialExtent(north=90, south=5, east=70, west=5, bottom=-40, top=40) + >>> B = SpatialExtent( + ... north=90, south=5, east=70, west=5, bottom=-40, top=40 + ... ) >>> A.spatial_relation_2d(B) 'in' >>> A.spatial_relation(B) 'overlap' - >>> B = SpatialExtent(north=90, south=5, east=70, west=5, bottom=-40, top=60) + >>> B = SpatialExtent( + ... north=90, south=5, east=70, west=5, bottom=-40, top=60 + ... ) >>> A.spatial_relation(B) 'overlap' - >>> B = SpatialExtent(north=90, south=5, east=70, west=5, bottom=-60, top=60) + >>> B = SpatialExtent( + ... north=90, south=5, east=70, west=5, bottom=-60, top=60 + ... ) >>> A.spatial_relation(B) 'in' - >>> A = SpatialExtent(north=80, south=60, east=60, west=10, bottom=-50, top=50) - >>> B = SpatialExtent(north=60, south=20, east=60, west=10, bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=60, east=60, west=10, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=60, south=20, east=60, west=10, bottom=-50, top=50 + ... ) >>> A.spatial_relation_2d(B) 'meet' >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=60, south=40, east=60, west=10, bottom=-50, top=50) - >>> B = SpatialExtent(north=80, south=60, east=60, west=10, bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=60, south=40, east=60, west=10, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=80, south=60, east=60, west=10, bottom=-50, top=50 + ... ) >>> A.spatial_relation_2d(B) 'meet' >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=60, west=40, bottom=-50, top=50) - >>> B = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=40, east=60, west=40, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=80, south=40, east=40, west=20, bottom=-50, top=50 + ... ) >>> A.spatial_relation_2d(B) 'meet' >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50) - >>> B = SpatialExtent(north=90, south=30, east=60, west=40, bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=40, east=40, west=20, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=90, south=30, east=60, west=40, bottom=-50, top=50 + ... ) >>> A.spatial_relation_2d(B) 'meet' >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50) - >>> B = SpatialExtent(north=70, south=50, east=60, west=40, bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=40, east=40, west=20, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=70, south=50, east=60, west=40, bottom=-50, top=50 + ... ) >>> A.spatial_relation_2d(B) 'meet' >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50) - >>> B = SpatialExtent(north=60, south=20, east=60, west=40, bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=40, east=40, west=20, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=60, south=20, east=60, west=40, bottom=-50, top=50 + ... ) >>> A.spatial_relation_2d(B) 'meet' >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50) - >>> B = SpatialExtent(north=40, south=20, east=60, west=40, bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=40, east=40, west=20, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=40, south=20, east=60, west=40, bottom=-50, top=50 + ... ) >>> A.spatial_relation_2d(B) 'disjoint' >>> A.spatial_relation(B) 'disjoint' - >>> A = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50) - >>> B = SpatialExtent(north=60, south=20, east=60, west=40, bottom=-60, top=60) + >>> A = SpatialExtent( + ... north=80, south=40, east=40, west=20, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=60, south=20, east=60, west=40, bottom=-60, top=60 + ... ) >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50) - >>> B = SpatialExtent(north=90, south=30, east=60, west=40, bottom=-40, top=40) + >>> A = SpatialExtent( + ... north=80, south=40, east=40, west=20, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=90, south=30, east=60, west=40, bottom=-40, top=40 + ... ) >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=0, top=50) - >>> B = SpatialExtent(north=80, south=40, east=60, west=20, bottom=-50, top=0) + >>> A = SpatialExtent( + ... north=80, south=40, east=60, west=20, bottom=0, top=50 + ... ) + >>> B = SpatialExtent( + ... north=80, south=40, east=60, west=20, bottom=-50, top=0 + ... ) >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=0, top=50) - >>> B = SpatialExtent(north=80, south=50, east=60, west=30, bottom=-50, top=0) + >>> A = SpatialExtent( + ... north=80, south=40, east=60, west=20, bottom=0, top=50 + ... ) + >>> B = SpatialExtent( + ... north=80, south=50, east=60, west=30, bottom=-50, top=0 + ... ) >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=0, top=50) - >>> B = SpatialExtent(north=70, south=50, east=50, west=30, bottom=-50, top=0) + >>> A = SpatialExtent( + ... north=80, south=40, east=60, west=20, bottom=0, top=50 + ... ) + >>> B = SpatialExtent( + ... north=70, south=50, east=50, west=30, bottom=-50, top=0 + ... ) >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=0, top=50) - >>> B = SpatialExtent(north=90, south=30, east=70, west=10, bottom=-50, top=0) + >>> A = SpatialExtent( + ... north=80, south=40, east=60, west=20, bottom=0, top=50 + ... ) + >>> B = SpatialExtent( + ... north=90, south=30, east=70, west=10, bottom=-50, top=0 + ... ) >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=0, top=50) - >>> B = SpatialExtent(north=70, south=30, east=50, west=10, bottom=-50, top=0) + >>> A = SpatialExtent( + ... north=80, south=40, east=60, west=20, bottom=0, top=50 + ... ) + >>> B = SpatialExtent( + ... north=70, south=30, east=50, west=10, bottom=-50, top=0 + ... ) >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=-50, top=0) - >>> B = SpatialExtent(north=80, south=40, east=60, west=20, bottom=0, top=50) + >>> A = SpatialExtent( + ... north=80, south=40, east=60, west=20, bottom=-50, top=0 + ... ) + >>> B = SpatialExtent( + ... north=80, south=40, east=60, west=20, bottom=0, top=50 + ... ) >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=-50, top=0) - >>> B = SpatialExtent(north=80, south=50, east=60, west=30, bottom=0, top=50) + >>> A = SpatialExtent( + ... north=80, south=40, east=60, west=20, bottom=-50, top=0 + ... ) + >>> B = SpatialExtent( + ... north=80, south=50, east=60, west=30, bottom=0, top=50 + ... ) >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=-50, top=0) - >>> B = SpatialExtent(north=70, south=50, east=50, west=30, bottom=0, top=50) + >>> A = SpatialExtent( + ... north=80, south=40, east=60, west=20, bottom=-50, top=0 + ... ) + >>> B = SpatialExtent( + ... north=70, south=50, east=50, west=30, bottom=0, top=50 + ... ) >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=-50, top=0) - >>> B = SpatialExtent(north=90, south=30, east=70, west=10, bottom=0, top=50) + >>> A = SpatialExtent( + ... north=80, south=40, east=60, west=20, bottom=-50, top=0 + ... ) + >>> B = SpatialExtent( + ... north=90, south=30, east=70, west=10, bottom=0, top=50 + ... ) >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=-50, top=0) - >>> B = SpatialExtent(north=70, south=30, east=50, west=10, bottom=0, top=50) + >>> A = SpatialExtent( + ... north=80, south=40, east=60, west=20, bottom=-50, top=0 + ... ) + >>> B = SpatialExtent( + ... north=70, south=30, east=50, west=10, bottom=0, top=50 + ... ) >>> A.spatial_relation(B) 'meet' - >>> A = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50) - >>> B = SpatialExtent(north=90, south=81, east=60, west=10, bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=90, south=81, east=60, west=10, bottom=-50, top=50 + ... ) >>> A.spatial_relation(B) 'disjoint' - >>> A = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50) - >>> B = SpatialExtent(north=90, south=80, east=60, west=10, bottom=-50, top=50) + >>> A = SpatialExtent( + ... north=80, south=20, east=60, west=10, bottom=-50, top=50 + ... ) + >>> B = SpatialExtent( + ... north=90, south=80, east=60, west=10, bottom=-50, top=50 + ... ) >>> A.spatial_relation(B) 'meet' @@ -1824,7 +2002,7 @@ def print_info(self): """Print information about this class in human readable style""" # 0123456789012345678901234567890 print( - " +-------------------- Spatial extent ----------------------------------------+" + " +-------------------- Spatial extent ----------------------------------------+" # noqa: E501 ) print(" | North:...................... " + str(self.get_north())) print(" | South:...................... " + str(self.get_south())) diff --git a/python/grass/temporal/spatial_topology_dataset_connector.py b/python/grass/temporal/spatial_topology_dataset_connector.py index 104a1491e39..93fe3270c43 100644 --- a/python/grass/temporal/spatial_topology_dataset_connector.py +++ b/python/grass/temporal/spatial_topology_dataset_connector.py @@ -13,6 +13,7 @@ :authors: Soeren Gebbert """ + import copy @@ -67,7 +68,8 @@ class SpatialTopologyDatasetConnector: meet=a@P >>> rlist = tmr.get_spatial_relations() >>> if "COVER" in rlist.keys(): - ... print(rlist["COVER"][0].get_id()) + ... print(rlist["COVER"][0].get_id()) + ... a@P """ @@ -318,7 +320,7 @@ def print_spatial_topology_info(self): """Print information about this class in human readable style""" print( - " +-------------------- Spatial Topology --------------------------------------+" + " +-------------------- Spatial Topology --------------------------------------+" # noqa: E501 ) # 0123456789012345678901234567890 if self.equivalent is not None: diff --git a/python/grass/temporal/spatio_temporal_relationships.py b/python/grass/temporal/spatio_temporal_relationships.py index cfc56644262..ab876d45ede 100644 --- a/python/grass/temporal/spatio_temporal_relationships.py +++ b/python/grass/temporal/spatio_temporal_relationships.py @@ -17,6 +17,7 @@ :authors: Soeren Gebbert """ + from datetime import datetime from .core import init_dbif from .abstract_dataset import AbstractDatasetComparisonKeyStartTime @@ -37,8 +38,6 @@ class SpatioTemporalTopologyBuilder: Example: - .. code-block:: python - # We have a space time raster dataset and build a map list # from all registered maps ordered by start time maps = strds.get_registered_maps_as_objects() @@ -73,6 +72,8 @@ class SpatioTemporalTopologyBuilder: # Dictionary like accessed map = tb["name@mapset"] + .. code-block:: python + >>> # Example with two lists of maps >>> import grass.temporal as tgis >>> import datetime @@ -80,14 +81,15 @@ class SpatioTemporalTopologyBuilder: >>> mapsA = [] >>> mapsB = [] >>> for i in range(4): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... check = mapA.set_relative_time(i, i + 1, "months") ... check = mapB.set_relative_time(i, i + 1, "months") ... mapsA.append(mapA) ... mapsB.append(mapB) + ... >>> # Build the topology between the two map lists >>> tb = SpatioTemporalTopologyBuilder() >>> tb.build(mapsA, mapsB, None) @@ -95,8 +97,11 @@ class SpatioTemporalTopologyBuilder: >>> for map in mapsA: ... if map.get_equal(): ... relations = map.get_equal() - ... print("Map %s has equal relation to map %s"%(map.get_name(), - ... relations[0].get_name())) + ... print( + ... "Map %s has equal relation to map %s" + ... % (map.get_name(), relations[0].get_name()) + ... ) + ... Map a0 has equal relation to map b0 Map a1 has equal relation to map b1 Map a2 has equal relation to map b2 @@ -105,8 +110,11 @@ class SpatioTemporalTopologyBuilder: >>> for map in mapsB: ... if map.get_equal(): ... relations = map.get_equal() - ... print("Map %s has equal relation to map %s"%(map.get_name(), - ... relations[0].get_name())) + ... print( + ... "Map %s has equal relation to map %s" + ... % (map.get_name(), relations[0].get_name()) + ... ) + ... Map b0 has equal relation to map a0 Map b1 has equal relation to map a1 Map b2 has equal relation to map a2 @@ -116,14 +124,15 @@ class SpatioTemporalTopologyBuilder: >>> mapsA = [] >>> mapsB = [] >>> for i in range(4): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... check = mapA.set_relative_time(i, i + 1, "months") ... check = mapB.set_relative_time(i + 1, i + 2, "months") ... mapsA.append(mapA) ... mapsB.append(mapB) + ... >>> # Build the topology between the two map lists >>> tb = SpatioTemporalTopologyBuilder() >>> tb.build(mapsA, mapsB, None) @@ -134,6 +143,7 @@ class SpatioTemporalTopologyBuilder: ... for key in m.keys(): ... if key not in ["NEXT", "PREV"]: ... print((key, m[key][0].get_temporal_extent_as_tuple())) + ... (0, 1) ('PRECEDES', (1, 2)) (1, 2) @@ -151,9 +161,9 @@ class SpatioTemporalTopologyBuilder: >>> mapsA = [] >>> mapsB = [] >>> for i in range(4): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... start = datetime.datetime(2000 + i, 1, 1) ... end = datetime.datetime(2000 + i + 1, 1, 1) @@ -163,6 +173,7 @@ class SpatioTemporalTopologyBuilder: ... check = mapB.set_absolute_time(start, end) ... mapsA.append(mapA) ... mapsB.append(mapB) + ... >>> # Build the topology between the two map lists >>> tb = SpatioTemporalTopologyBuilder() >>> tb.build(mapsA, mapsB, None) @@ -173,6 +184,7 @@ class SpatioTemporalTopologyBuilder: ... for key in m.keys(): ... if key not in ["NEXT", "PREV"]: ... print((key, m[key][0].get_temporal_extent_as_tuple())) + ... (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0)) ('PRECEDES', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0))) (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0)) @@ -190,9 +202,9 @@ class SpatioTemporalTopologyBuilder: >>> mapsA = [] >>> mapsB = [] >>> for i in range(4): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... start = datetime.datetime(2000 + i, 1, 1) ... end = datetime.datetime(2000 + i + 1, 1, 1) @@ -202,6 +214,7 @@ class SpatioTemporalTopologyBuilder: ... check = mapB.set_absolute_time(start, end) ... mapsA.append(mapA) ... mapsB.append(mapB) + ... >>> # Build the topology between the two map lists >>> tb = SpatioTemporalTopologyBuilder() >>> tb.build(mapsA, mapsB, None) @@ -212,6 +225,7 @@ class SpatioTemporalTopologyBuilder: ... for key in m.keys(): ... if key not in ["NEXT", "PREV"]: ... print((key, m[key][0].get_temporal_extent_as_tuple())) + ... (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0)) ('DURING', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) ('STARTS', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) @@ -234,9 +248,9 @@ class SpatioTemporalTopologyBuilder: >>> mapsA = [] >>> mapsB = [] >>> for i in range(4): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... start = datetime.datetime(2000 + i, 1, 1) ... end = datetime.datetime(2000 + i + 2, 1, 1) @@ -246,6 +260,7 @@ class SpatioTemporalTopologyBuilder: ... check = mapB.set_absolute_time(start, end) ... mapsA.append(mapA) ... mapsB.append(mapB) + ... >>> # Build the topology between the two map lists >>> tb = SpatioTemporalTopologyBuilder() >>> tb.build(mapsA, mapsB, None) @@ -256,6 +271,7 @@ class SpatioTemporalTopologyBuilder: ... for key in m.keys(): ... if key not in ["NEXT", "PREV"]: ... print((key, m[key][0].get_temporal_extent_as_tuple())) + ... (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0)) ('OVERLAPS', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) ('DURING', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) @@ -283,9 +299,9 @@ class SpatioTemporalTopologyBuilder: >>> mapsA = [] >>> mapsB = [] >>> for i in range(4): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... start = datetime.datetime(2000, 1, 1, 0, 0, i) ... end = datetime.datetime(2000, 1, 1, 0, 0, i + 2) @@ -295,6 +311,7 @@ class SpatioTemporalTopologyBuilder: ... check = mapB.set_absolute_time(start, end) ... mapsA.append(mapA) ... mapsB.append(mapB) + ... >>> # Build the topology between the two map lists >>> tb = SpatioTemporalTopologyBuilder() >>> tb.build(mapsA, mapsB, None) @@ -305,6 +322,7 @@ class SpatioTemporalTopologyBuilder: ... for key in m.keys(): ... if key not in ["NEXT", "PREV"]: ... print((key, m[key][0].get_temporal_extent_as_tuple())) + ... (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 1, 1, 0, 0, 2)) ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))) ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))) @@ -325,12 +343,13 @@ class SpatioTemporalTopologyBuilder: >>> mapsA = [] >>> for i in range(4): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) ... start = datetime.datetime(2000, 1, 1, 0, 0, i) ... end = datetime.datetime(2000, 1, 1, 0, 0, i + 2) ... check = mapA.set_absolute_time(start, end) ... mapsA.append(mapA) + ... >>> tb = SpatioTemporalTopologyBuilder() >>> tb.build(mapsA) >>> # Check relations of mapsA @@ -340,6 +359,7 @@ class SpatioTemporalTopologyBuilder: ... for key in m.keys(): ... if key not in ["NEXT", "PREV"]: ... print((key, m[key][0].get_temporal_extent_as_tuple())) + ... (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 1, 1, 0, 0, 2)) ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))) ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))) @@ -355,7 +375,7 @@ class SpatioTemporalTopologyBuilder: ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))) ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))) - """ + """ # noqa: E501 def __init__(self): self._reset() @@ -888,70 +908,94 @@ def create_temporal_relation_sql_where_statement( >>> # Relative time >>> start = 1 >>> end = 2 - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False) + >>> create_temporal_relation_sql_where_statement(start, end, use_start=False) >>> create_temporal_relation_sql_where_statement(start, end) '((start_time >= 1 and start_time < 2) )' - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=True) + >>> create_temporal_relation_sql_where_statement(start, end, use_start=True) '((start_time >= 1 and start_time < 2) )' - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False, use_during=True) + >>> create_temporal_relation_sql_where_statement( + ... start, end, use_start=False, use_during=True + ... ) '(((start_time > 1 and end_time < 2) OR (start_time >= 1 and end_time < 2) OR (start_time > 1 and end_time <= 2)))' - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False, use_overlap=True) + >>> create_temporal_relation_sql_where_statement( + ... start, end, use_start=False, use_overlap=True + ... ) '(((start_time < 1 and end_time > 1 and end_time < 2) OR (start_time < 2 and start_time > 1 and end_time > 2)))' - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False, use_contain=True) + >>> create_temporal_relation_sql_where_statement( + ... start, end, use_start=False, use_contain=True + ... ) '(((start_time < 1 and end_time > 2) OR (start_time <= 1 and end_time > 2) OR (start_time < 1 and end_time >= 2)))' - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False, use_equal=True) + >>> create_temporal_relation_sql_where_statement( + ... start, end, use_start=False, use_equal=True + ... ) '((start_time = 1 and end_time = 2))' - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False, use_follows=True) + >>> create_temporal_relation_sql_where_statement( + ... start, end, use_start=False, use_follows=True + ... ) '((start_time = 2))' - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False, use_precedes=True) + >>> create_temporal_relation_sql_where_statement( + ... start, end, use_start=False, use_precedes=True + ... ) '((end_time = 1))' - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=True, use_during=True, use_overlap=True, use_contain=True, - ... use_equal=True, use_follows=True, use_precedes=True) + >>> create_temporal_relation_sql_where_statement( + ... start, + ... end, + ... use_start=True, + ... use_during=True, + ... use_overlap=True, + ... use_contain=True, + ... use_equal=True, + ... use_follows=True, + ... use_precedes=True, + ... ) '((start_time >= 1 and start_time < 2) OR ((start_time > 1 and end_time < 2) OR (start_time >= 1 and end_time < 2) OR (start_time > 1 and end_time <= 2)) OR ((start_time < 1 and end_time > 1 and end_time < 2) OR (start_time < 2 and start_time > 1 and end_time > 2)) OR ((start_time < 1 and end_time > 2) OR (start_time <= 1 and end_time > 2) OR (start_time < 1 and end_time >= 2)) OR (start_time = 1 and end_time = 2) OR (start_time = 2) OR (end_time = 1))' >>> # Absolute time >>> start = datetime(2001, 1, 1, 12, 30) >>> end = datetime(2001, 3, 31, 14, 30) - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False) + >>> create_temporal_relation_sql_where_statement(start, end, use_start=False) >>> create_temporal_relation_sql_where_statement(start, end) "((start_time >= '2001-01-01 12:30:00' and start_time < '2001-03-31 14:30:00') )" - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=True) + >>> create_temporal_relation_sql_where_statement(start, end, use_start=True) "((start_time >= '2001-01-01 12:30:00' and start_time < '2001-03-31 14:30:00') )" - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False, use_during=True) + >>> create_temporal_relation_sql_where_statement( + ... start, end, use_start=False, use_during=True + ... ) "(((start_time > '2001-01-01 12:30:00' and end_time < '2001-03-31 14:30:00') OR (start_time >= '2001-01-01 12:30:00' and end_time < '2001-03-31 14:30:00') OR (start_time > '2001-01-01 12:30:00' and end_time <= '2001-03-31 14:30:00')))" - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False, use_overlap=True) + >>> create_temporal_relation_sql_where_statement( + ... start, end, use_start=False, use_overlap=True + ... ) "(((start_time < '2001-01-01 12:30:00' and end_time > '2001-01-01 12:30:00' and end_time < '2001-03-31 14:30:00') OR (start_time < '2001-03-31 14:30:00' and start_time > '2001-01-01 12:30:00' and end_time > '2001-03-31 14:30:00')))" - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False, use_contain=True) + >>> create_temporal_relation_sql_where_statement( + ... start, end, use_start=False, use_contain=True + ... ) "(((start_time < '2001-01-01 12:30:00' and end_time > '2001-03-31 14:30:00') OR (start_time <= '2001-01-01 12:30:00' and end_time > '2001-03-31 14:30:00') OR (start_time < '2001-01-01 12:30:00' and end_time >= '2001-03-31 14:30:00')))" - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False, use_equal=True) + >>> create_temporal_relation_sql_where_statement( + ... start, end, use_start=False, use_equal=True + ... ) "((start_time = '2001-01-01 12:30:00' and end_time = '2001-03-31 14:30:00'))" - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False, use_follows=True) + >>> create_temporal_relation_sql_where_statement( + ... start, end, use_start=False, use_follows=True + ... ) "((start_time = '2001-03-31 14:30:00'))" - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=False, use_precedes=True) + >>> create_temporal_relation_sql_where_statement( + ... start, end, use_start=False, use_precedes=True + ... ) "((end_time = '2001-01-01 12:30:00'))" - >>> create_temporal_relation_sql_where_statement(start, end, - ... use_start=True, use_during=True, use_overlap=True, use_contain=True, - ... use_equal=True, use_follows=True, use_precedes=True) + >>> create_temporal_relation_sql_where_statement( + ... start, + ... end, + ... use_start=True, + ... use_during=True, + ... use_overlap=True, + ... use_contain=True, + ... use_equal=True, + ... use_follows=True, + ... use_precedes=True, + ... ) "((start_time >= '2001-01-01 12:30:00' and start_time < '2001-03-31 14:30:00') OR ((start_time > '2001-01-01 12:30:00' and end_time < '2001-03-31 14:30:00') OR (start_time >= '2001-01-01 12:30:00' and end_time < '2001-03-31 14:30:00') OR (start_time > '2001-01-01 12:30:00' and end_time <= '2001-03-31 14:30:00')) OR ((start_time < '2001-01-01 12:30:00' and end_time > '2001-01-01 12:30:00' and end_time < '2001-03-31 14:30:00') OR (start_time < '2001-03-31 14:30:00' and start_time > '2001-01-01 12:30:00' and end_time > '2001-03-31 14:30:00')) OR ((start_time < '2001-01-01 12:30:00' and end_time > '2001-03-31 14:30:00') OR (start_time <= '2001-01-01 12:30:00' and end_time > '2001-03-31 14:30:00') OR (start_time < '2001-01-01 12:30:00' and end_time >= '2001-03-31 14:30:00')) OR (start_time = '2001-01-01 12:30:00' and end_time = '2001-03-31 14:30:00') OR (start_time = '2001-03-31 14:30:00') OR (end_time = '2001-01-01 12:30:00'))" - """ + """ # noqa: E501 where = "(" diff --git a/python/grass/temporal/temporal_algebra.py b/python/grass/temporal/temporal_algebra.py index bd74d6799ff..db35f03f071 100644 --- a/python/grass/temporal/temporal_algebra.py +++ b/python/grass/temporal/temporal_algebra.py @@ -16,7 +16,7 @@ >>> p = tgis.TemporalAlgebraLexer() >>> p.build() >>> p.debug = True - >>> expression = "C = A : B" + >>> expression = "C = A : B" >>> p.test(expression) C = A : B LexToken(NAME,'C',1,0) @@ -24,7 +24,7 @@ LexToken(NAME,'A',1,4) LexToken(T_SELECT,':',1,6) LexToken(NAME,'B',1,8) - >>> expression = "C = test1 !: test2" + >>> expression = "C = test1 !: test2" >>> p.test(expression) C = test1 !: test2 LexToken(NAME,'C',1,0) @@ -32,7 +32,7 @@ LexToken(NAME,'test1',1,4) LexToken(T_NOT_SELECT,'!:',1,10) LexToken(NAME,'test2',1,13) - >>> expression = "C = test1 {:,equal} test2" + >>> expression = "C = test1 {:,equal} test2" >>> p.test(expression) C = test1 {:,equal} test2 LexToken(NAME,'C',1,0) @@ -40,7 +40,7 @@ LexToken(NAME,'test1',1,4) LexToken(T_SELECT_OPERATOR,'{:,equal}',1,10) LexToken(NAME,'test2',1,20) - >>> expression = "C = test1 {!:,equal} test2" + >>> expression = "C = test1 {!:,equal} test2" >>> p.test(expression) C = test1 {!:,equal} test2 LexToken(NAME,'C',1,0) @@ -48,7 +48,7 @@ LexToken(NAME,'test1',1,4) LexToken(T_SELECT_OPERATOR,'{!:,equal}',1,10) LexToken(NAME,'test2',1,21) - >>> expression = "C = test1 # test2" + >>> expression = "C = test1 # test2" >>> p.test(expression) C = test1 # test2 LexToken(NAME,'C',1,0) @@ -56,7 +56,7 @@ LexToken(NAME,'test1',1,4) LexToken(HASH,'#',1,10) LexToken(NAME,'test2',1,12) - >>> expression = "C = test1 {#} test2" + >>> expression = "C = test1 {#} test2" >>> p.test(expression) C = test1 {#} test2 LexToken(NAME,'C',1,0) @@ -64,7 +64,7 @@ LexToken(NAME,'test1',1,4) LexToken(T_HASH_OPERATOR,'{#}',1,10) LexToken(NAME,'test2',1,14) - >>> expression = "C = test1 {#,equal} test2" + >>> expression = "C = test1 {#,equal} test2" >>> p.test(expression) C = test1 {#,equal} test2 LexToken(NAME,'C',1,0) @@ -72,7 +72,7 @@ LexToken(NAME,'test1',1,4) LexToken(T_HASH_OPERATOR,'{#,equal}',1,10) LexToken(NAME,'test2',1,20) - >>> expression = "C = test1 {#,equal|during} test2" + >>> expression = "C = test1 {#,equal|during} test2" >>> p.test(expression) C = test1 {#,equal|during} test2 LexToken(NAME,'C',1,0) @@ -80,7 +80,7 @@ LexToken(NAME,'test1',1,4) LexToken(T_HASH_OPERATOR,'{#,equal|during}',1,10) LexToken(NAME,'test2',1,27) - >>> expression = "E = test1 : test2 !: test1" + >>> expression = "E = test1 : test2 !: test1" >>> p.test(expression) E = test1 : test2 !: test1 LexToken(NAME,'E',1,0) @@ -90,7 +90,7 @@ LexToken(NAME,'test2',1,12) LexToken(T_NOT_SELECT,'!:',1,18) LexToken(NAME,'test1',1,21) - >>> expression = 'D = buff_t(test1,"10 months")' + >>> expression = 'D = buff_t(test1,"10 months")' >>> p.test(expression) D = buff_t(test1,"10 months") LexToken(NAME,'D',1,0) @@ -104,7 +104,7 @@ LexToken(NAME,'months',1,21) LexToken(QUOTE,'"',1,27) LexToken(RPAREN,')',1,28) - >>> expression = 'H = tsnap(test1)' + >>> expression = "H = tsnap(test1)" >>> p.test(expression) H = tsnap(test1) LexToken(NAME,'H',1,0) @@ -113,7 +113,7 @@ LexToken(LPAREN,'(',1,9) LexToken(NAME,'test1',1,10) LexToken(RPAREN,')',1,15) - >>> expression = 'H = tsnap(test2 {:,during} buff_t(test1, "1 days"))' + >>> expression = 'H = tsnap(test2 {:,during} buff_t(test1, "1 days"))' >>> p.test(expression) H = tsnap(test2 {:,during} buff_t(test1, "1 days")) LexToken(NAME,'H',1,0) @@ -132,7 +132,7 @@ LexToken(QUOTE,'"',1,48) LexToken(RPAREN,')',1,49) LexToken(RPAREN,')',1,50) - >>> expression = 'H = tshift(test2 {:,during} buff_t(test1, "1 days"), "1 months")' + >>> expression = 'H = tshift(test2 {:,during} buff_t(test1, "1 days"), "1 months")' >>> p.test(expression) H = tshift(test2 {:,during} buff_t(test1, "1 days"), "1 months") LexToken(NAME,'H',1,0) @@ -156,7 +156,7 @@ LexToken(NAME,'months',1,56) LexToken(QUOTE,'"',1,62) LexToken(RPAREN,')',1,63) - >>> expression = 'H = tshift(A , 10)' + >>> expression = "H = tshift(A , 10)" >>> p.test(expression) H = tshift(A , 10) LexToken(NAME,'H',1,0) @@ -167,7 +167,7 @@ LexToken(COMMA,',',1,13) LexToken(INT,10,1,15) LexToken(RPAREN,')',1,17) - >>> expression = 'H = if(td(A) > 10, A)' + >>> expression = "H = if(td(A) > 10, A)" >>> p.test(expression) H = if(td(A) > 10, A) LexToken(NAME,'H',1,0) @@ -183,7 +183,7 @@ LexToken(COMMA,',',1,17) LexToken(NAME,'A',1,19) LexToken(RPAREN,')',1,20) - >>> expression = 'H = if(td(A) > 10, A, B)' + >>> expression = "H = if(td(A) > 10, A, B)" >>> p.test(expression) H = if(td(A) > 10, A, B) LexToken(NAME,'H',1,0) @@ -201,7 +201,7 @@ LexToken(COMMA,',',1,20) LexToken(NAME,'B',1,22) LexToken(RPAREN,')',1,23) - >>> expression = 'I = if(equals,td(A) > 10 {||,equals} td(B) < 10, A)' + >>> expression = "I = if(equals,td(A) > 10 {||,equals} td(B) < 10, A)" >>> p.test(expression) I = if(equals,td(A) > 10 {||,equals} td(B) < 10, A) LexToken(NAME,'I',1,0) @@ -226,7 +226,7 @@ LexToken(COMMA,',',1,47) LexToken(NAME,'A',1,49) LexToken(RPAREN,')',1,50) - >>> expression = 'I = if(equals,td(A) > 10 || start_day() < 10, A)' + >>> expression = "I = if(equals,td(A) > 10 || start_day() < 10, A)" >>> p.test(expression) I = if(equals,td(A) > 10 || start_day() < 10, A) LexToken(NAME,'I',1,0) @@ -251,7 +251,7 @@ LexToken(COMMA,',',1,44) LexToken(NAME,'A',1,46) LexToken(RPAREN,')',1,47) - >>> expression = 'E = if({equals},td(A) >= 4 {&&,contain} td(B) == 2, C : D)' + >>> expression = "E = if({equals},td(A) >= 4 {&&,contain} td(B) == 2, C : D)" >>> p.test(expression) E = if({equals},td(A) >= 4 {&&,contain} td(B) == 2, C : D) LexToken(NAME,'E',1,0) @@ -278,7 +278,7 @@ LexToken(T_SELECT,':',1,54) LexToken(NAME,'D',1,56) LexToken(RPAREN,')',1,57) - >>> expression = 'F = if({equals},A {#,equal}, B, C : D)' + >>> expression = "F = if({equals},A {#,equal}, B, C : D)" >>> p.test(expression) F = if({equals},A {#,equal}, B, C : D) LexToken(NAME,'F',1,0) @@ -299,14 +299,14 @@ >>> p = tgis.TemporalAlgebraParser() >>> p.run = False >>> p.debug = True - >>> expression = "D = A {!:} B {:,during} C" + >>> expression = "D = A {!:} B {:,during} C" >>> print(expression) D = A {!:} B {:,during} C >>> ret = p.parse(expression) A* = A {!:} B A** = A* {:,during} C D = A** - >>> expression = "D = A {:} B {!:,during} C" + >>> expression = "D = A {:} B {!:,during} C" >>> print(expression) D = A {:} B {!:,during} C >>> ret = p.parse(expression) @@ -315,52 +315,52 @@ D = A** >>> p.run = False >>> p.debug = False - >>> expression = "C = test1 : test2" + >>> expression = "C = test1 : test2" >>> print(expression) C = test1 : test2 - >>> ret = p.parse(expression, 'stvds') - >>> expression = 'D = buff_t(test1,"10 months")' + >>> ret = p.parse(expression, "stvds") + >>> expression = 'D = buff_t(test1,"10 months")' >>> print(expression) D = buff_t(test1,"10 months") - >>> ret = p.parse(expression, 'stvds') - >>> expression = 'E = test2 {:,during} buff_t(test1,"1 days")' + >>> ret = p.parse(expression, "stvds") + >>> expression = 'E = test2 {:,during} buff_t(test1,"1 days")' >>> print(expression) E = test2 {:,during} buff_t(test1,"1 days") - >>> ret = p.parse(expression, 'stvds') - >>> expression = 'F = test2 {:,equal} buff_t(test1,"1 days")' + >>> ret = p.parse(expression, "stvds") + >>> expression = 'F = test2 {:,equal} buff_t(test1,"1 days")' >>> print(expression) F = test2 {:,equal} buff_t(test1,"1 days") - >>> ret = p.parse(expression, 'stvds') + >>> ret = p.parse(expression, "stvds") >>> p.debug = True - >>> expression = 'H = tsnap(test2 {:,during} buff_t(test1, "1 days"))' - >>> ret = p.parse(expression, 'stvds') + >>> expression = 'H = tsnap(test2 {:,during} buff_t(test1, "1 days"))' + >>> ret = p.parse(expression, "stvds") test1* = buff_t( test1 , " 1 days " ) test2* = test2 {:,during} test1* test2** = tsnap( test2* ) H = test2** - >>> expression = 'H = tshift(test2 {:,during} test1, "1 days")' - >>> ret = p.parse(expression, 'stvds') + >>> expression = 'H = tshift(test2 {:,during} test1, "1 days")' + >>> ret = p.parse(expression, "stvds") test2* = test2 {:,during} test1 test2** = tshift( test2* , " 1 days " ) H = test2** - >>> expression = 'H = tshift(H, 3)' - >>> ret = p.parse(expression, 'stvds') + >>> expression = "H = tshift(H, 3)" + >>> ret = p.parse(expression, "stvds") H* = tshift( H , 3 ) H = H* - >>> expression = 'C = if(td(A) == 2, A)' - >>> ret = p.parse(expression, 'stvds') + >>> expression = "C = if(td(A) == 2, A)" + >>> ret = p.parse(expression, "stvds") td(A) td(A) == 2 A* = if condition None then A C = A* - >>> expression = 'C = if(td(A) == 5, A, B)' - >>> ret = p.parse(expression, 'stvds') + >>> expression = "C = if(td(A) == 5, A, B)" + >>> ret = p.parse(expression, "stvds") td(A) td(A) == 5 A* = if condition None then A else B C = A* - >>> expression = 'C = if(td(A) == 5 || start_date(A) > "2010-01-01", A, B)' - >>> ret = p.parse(expression, 'stvds') + >>> expression = 'C = if(td(A) == 5 || start_date(A) > "2010-01-01", A, B)' + >>> ret = p.parse(expression, "stvds") td(A) td(A) == 5 start_date A > "2010-01-01" @@ -371,7 +371,7 @@ >>> p = tgis.TemporalAlgebraLexer() >>> p.build() >>> p.debug = True - >>> expression = "D = strds(A) : stvds(B) : str3ds(C)" + >>> expression = "D = strds(A) : stvds(B) : str3ds(C)" >>> p.test(expression) D = strds(A) : stvds(B) : str3ds(C) LexToken(NAME,'D',1,0) @@ -394,7 +394,7 @@ >>> p = tgis.TemporalAlgebraLexer() >>> p.build() >>> p.debug = True - >>> expression = "R = if(A {#,during} stvds(C) == 1, A)" + >>> expression = "R = if(A {#,during} stvds(C) == 1, A)" >>> p.test(expression) R = if(A {#,during} stvds(C) == 1, A) LexToken(NAME,'R',1,0) @@ -416,7 +416,7 @@ >>> p = tgis.TemporalAlgebraLexer() >>> p.build() >>> p.debug = True - >>> expression = "R = if({during}, stvds(C) {#,contains} A == 2, A)" + >>> expression = "R = if({during}, stvds(C) {#,contains} A == 2, A)" >>> p.test(expression) R = if({during}, stvds(C) {#,contains} A == 2, A) LexToken(NAME,'R',1,0) @@ -525,7 +525,8 @@ class TemporalAlgebraLexer: # and in relative units in case of relative time. # The end_time() will be represented by null() in case of a time instance. "start_doy": "START_DOY", # Day of year (doy) from the start time [1 - 366] - "start_dow": "START_DOW", # Day of week (dow) from the start time [1 - 7], the start of the week is Monday == 1 + "start_dow": "START_DOW", # Day of week (dow) from the start time [1 - 7], + # the start of the week is Monday == 1 "start_year": "START_YEAR", # The year of the start time [0 - 9999] "start_month": "START_MONTH", # The month of the start time [1 - 12] "start_week": "START_WEEK", # Week of year of the start time [1 - 54] @@ -534,7 +535,8 @@ class TemporalAlgebraLexer: "start_minute": "START_MINUTE", # The minute of the start time [0 - 59] "start_second": "START_SECOND", # The second of the start time [0 - 59] "end_doy": "END_DOY", # Day of year (doy) from the end time [1 - 366] - "end_dow": "END_DOW", # Day of week (dow) from the end time [1 - 7], the start of the week is Monday == 1 + "end_dow": "END_DOW", # Day of week (dow) from the end time [1 - 7], the + # start of the week is Monday == 1 "end_year": "END_YEAR", # The year of the end time [0 - 9999] "end_month": "END_MONTH", # The month of the end time [1 - 12] "end_week": "END_WEEK", # Week of year of the end time [1 - 54] @@ -583,11 +585,9 @@ class TemporalAlgebraLexer: ) # Regular expression rules for simple tokens - t_T_SELECT_OPERATOR = r"\{[!]?[:][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}" - t_T_HASH_OPERATOR = ( - r"\{[#][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}" - ) - t_T_COMP_OPERATOR = r"\{(\|\||&&)[,][a-zA-Z\| ]*[,]?[\|&]?([,])?([lrudi]|left|right|union|disjoint|intersect)?\}" + t_T_SELECT_OPERATOR = r"\{[!]?[:][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}" # noqa: E501 + t_T_HASH_OPERATOR = r"\{[#][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}" # noqa: E501 + t_T_COMP_OPERATOR = r"\{(\|\||&&)[,][a-zA-Z\| ]*[,]?[\|&]?([,])?([lrudi]|left|right|union|disjoint|intersect)?\}" # noqa: E501 t_T_REL_OPERATOR = r"\{([a-zA-Z\| ])+\}" t_T_SELECT = r":" t_T_NOT_SELECT = r"!:" @@ -611,7 +611,7 @@ class TemporalAlgebraLexer: # Read time string and convert it into a date object def t_DATETIME(self, t): - r'"\d\d\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])[ T](0[0-9]|1(0-9)|2[0-4]):(0[0-9]|[1-5][0-9]|60):(0[0-9]|[1-5][0-9]|60)"' + r'"\d\d\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])[ T](0[0-9]|1(0-9)|2[0-4]):(0[0-9]|[1-5][0-9]|60):(0[0-9]|[1-5][0-9]|60)"' # noqa: E501 # t.value = int(t.value) return t @@ -790,18 +790,15 @@ def __init__( time_suffix=None, ): self.run = run - self.dry_run = ( - dry_run # Compute the processes and output but Do not start the processes - ) - self.process_chain_dict = ( - {} - ) # This dictionary stores all processes, as well as the maps to register and remove - self.process_chain_dict[ - "processes" - ] = [] # The mapcalc and v.patch module calls - self.process_chain_dict[ - "register" - ] = [] # Maps that must be registered/updated or inserted in a new STDS + # Compute the processes and output but Do not start the processes + self.dry_run = dry_run + # This dictionary stores all processes, as well as the maps to register and + # remove + self.process_chain_dict = {} + # The mapcalc and v.patch module calls + self.process_chain_dict["processes"] = [] + # Maps that must be registered/updated or inserted in a new STDS + self.process_chain_dict["register"] = [] self.process_chain_dict["remove"] = [] # The g.remove module calls self.process_chain_dict["STDS"] = {} # The STDS that must be created @@ -856,7 +853,8 @@ def setup_common_granularity(self, expression, stdstype="strds", lexer=None): space time datasets in the expression to generate the map lists. This function will analyze the expression to detect space time datasets - and computes the common granularity from all granularities of the input space time datasets. + and computes the common granularity from all granularities of the input space + time datasets. This granularity is then be used to generate the map lists. Hence, all maps from all STDS will have equidistant temporal extents. The only meaningful @@ -864,8 +862,9 @@ def setup_common_granularity(self, expression, stdstype="strds", lexer=None): :param expression: The algebra expression to analyze - :param lexer: The temporal algebra lexer (select, raster, voxel, vector) that should be used to - parse the expression, default is TemporalAlgebraLexer + :param lexer: The temporal algebra lexer (select, raster, voxel, vector) that + should be used to parse the expression, default is + TemporalAlgebraLexer :return: True if successful, False otherwise """ @@ -921,7 +920,8 @@ def setup_common_granularity(self, expression, stdstype="strds", lexer=None): if stds.check_temporal_topology() is False: self.msgr.error( _( - "All input space time datasets must have a valid temporal topology." + "All input space time datasets must have a valid temporal " + "topology." ) ) return False @@ -1010,7 +1010,8 @@ def generate_new_map( copied to mapA :param rename: Specifies if the generated map get a random name or get the id from the base map. - :param remove: Set this True if this map is an intermediate or empty map that should be removed + :param remove: Set this True if this map is an intermediate or empty map that + should be removed :return: Map object """ # Generate an intermediate name for the result map list. @@ -1126,7 +1127,8 @@ def set_temporal_extent_list(self, maplist, topolist=["EQUAL"], temporal="l"): map_new = self.generate_new_map( base_map=map_i, bool_op="and", copy=True, rename=True ) - # Combine temporal and spatial extents of intermediate map with related maps. + # Combine temporal and spatial extents of intermediate map with related + # maps. for topo in topolist: if topo in tbrelations.keys(): for map_j in tbrelations[topo]: @@ -1150,21 +1152,22 @@ def set_temporal_extent_list(self, maplist, topolist=["EQUAL"], temporal="l"): ) if self.debug: print(map_new.get_id(), map_j.get_id()) - # Stop the loop if no temporal or spatial relationship exist. + # Stop the loop if no temporal or spatial relationship + # exist. if returncode == 0: break # Append map to result map list. elif returncode == 1: - # print(map_new.get_id() + " " + str(map_new.get_temporal_extent_as_tuple())) + # print(map_new.get_id() + " " + + # str(map_new.get_temporal_extent_as_tuple())) # print(map_new.condition_value) # print(map_new.cmd_list) # resultlist.append(map_new) resultdict[map_new.get_id()] = map_new # Create r.mapcalc expression string for the operation. - # cmdstring = self.build_command_string(s_expr_a = map_new, - # s_expr_b = map_j, - # operator = function) + # cmdstring = self.build_command_string( + # s_expr_a = map_new, s_expr_b = map_j, operator = function) # Conditional append of module command. # map_new.cmd_list = cmdstring if returncode == 0: @@ -1221,9 +1224,10 @@ def check_stds(self, input, clear=False, stds_type=None, check_type=True): :param input: Name of space time data set as string or list of maps. :param clear: Reset the stored conditional values to empty list. - :param check_type: Check the type of the space time dataset to match the global stds type - :param stds_type: The type of the space time dataset to be opened, if not provided - then self.stdstype will be used + :param check_type: Check the type of the space time dataset to match the global + stds type + :param stds_type: The type of the space time dataset to be opened, if not + provided then self.stdstype will be used :return: List of maps. """ @@ -1273,16 +1277,16 @@ def check_stds(self, input, clear=False, stds_type=None, check_type=True): elif map_i.is_time_absolute() and self.temporaltype == "relative": self.msgr.fatal( _( - "Wrong temporal type of space time dataset <%s> \ - <%s> time is required" + "Wrong temporal type of space time dataset " + "<%s> <%s> time is required" ) % (id_input, self.temporaltype) ) elif map_i.is_time_relative() and self.temporaltype == "absolute": self.msgr.fatal( _( - "Wrong temporal type of space time dataset <%s> \ - <%s> time is required" + "Wrong temporal type of space time dataset " + "<%s> <%s> time is required" ) % (id_input, self.temporaltype) ) @@ -1321,7 +1325,8 @@ def _check_spatial_topology_entries(self, spatial_topo_list, spatial_relations): Return True if no spatial relation list is provided or if one spatial relation was found - :param spatial_topo_list: The spatial relations that were defined in the expression + :param spatial_topo_list: The spatial relations that were defined in the + expression :param spatial_relations: The spatial relations of a single map object :return: True if a spatial topological relation was found, False if not @@ -1342,8 +1347,8 @@ def _check_spatial_topology_entries(self, spatial_topo_list, spatial_relations): return spatial_topo_check def _check_spatial_topology_relation(self, spatial_topo_list, map_a, map_b): - """Check if map_b has one of the spatial topological relations to map_a that is defined - in spatial_topo_list + """Check if map_b has one of the spatial topological relations to map_a that is + defined in spatial_topo_list :param spatial_topo_list: :param map_a: @@ -1373,9 +1378,11 @@ def _check_topology(self, topolist): :param topolist: List of strings of temporal and spatial relations. - :return: A tuple of spatial and temporal topology lists (temporal_topo_list, spatial_topo_list) + :return: A tuple of spatial and temporal topology lists + (temporal_topo_list, spatial_topo_list) - :raises: This method will raise a syntax error in case the topology name is unknown + :raises: This method will raise a syntax error in case the topology name is + unknown """ temporal_topo_list = [] spatial_topo_list = [] @@ -1429,7 +1436,7 @@ def build_spatio_temporal_topology_list( .. code-block:: python - # Example with two lists of maps + >>> # Example with two lists of maps >>> import grass.temporal as tgis >>> tgis.init(True) >>> l = tgis.TemporalAlgebraParser() @@ -1437,22 +1444,28 @@ def build_spatio_temporal_topology_list( >>> mapsA = [] >>> mapsB = [] >>> for i in range(10): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) ... mapA.uid = idA - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... mapB.uid = idB ... check = mapA.set_relative_time(i, i + 1, "months") ... check = mapB.set_relative_time(i, i + 1, "months") ... mapsA.append(mapA) ... mapsB.append(mapB) - >>> resultlist = l.build_spatio_temporal_topology_list(mapsA, mapsB, ['EQUAL']) + ... + >>> resultlist = l.build_spatio_temporal_topology_list( + ... mapsA, mapsB, ["EQUAL"] + ... ) >>> for map in resultlist: ... if map.get_equal(): ... relations = map.get_equal() - ... print("Map %s has equal relation to map %s"%(map.get_name(), - ... relations[0].get_name())) + ... print( + ... "Map %s has equal relation to map %s" + ... % (map.get_name(), relations[0].get_name()) + ... ) + ... Map a0 has equal relation to map b0 Map a1 has equal relation to map b1 Map a2 has equal relation to map b2 @@ -1463,29 +1476,37 @@ def build_spatio_temporal_topology_list( Map a7 has equal relation to map b7 Map a8 has equal relation to map b8 Map a9 has equal relation to map b9 - >>> resultlist = l.build_spatio_temporal_topology_list(mapsA, mapsB, ['DURING']) + >>> resultlist = l.build_spatio_temporal_topology_list( + ... mapsA, mapsB, ["DURING"] + ... ) >>> print(resultlist) [] >>> # Create two list of maps with equal time stamps >>> mapsA = [] >>> mapsB = [] >>> for i in range(10): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) ... mapA.uid = idA - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... mapB.uid = idB ... check = mapA.set_relative_time(i, i + 1, "months") ... check = mapB.set_relative_time(i, i + 2, "months") ... mapsA.append(mapA) ... mapsB.append(mapB) - >>> resultlist = l.build_spatio_temporal_topology_list(mapsA, mapsB, ['starts','during']) + ... + >>> resultlist = l.build_spatio_temporal_topology_list( + ... mapsA, mapsB, ["starts", "during"] + ... ) >>> for map in resultlist: ... if map.get_starts(): ... relations = map.get_starts() - ... print("Map %s has start relation to map %s"%(map.get_name(), - ... relations[0].get_name())) + ... print( + ... "Map %s has start relation to map %s" + ... % (map.get_name(), relations[0].get_name()) + ... ) + ... Map a0 has start relation to map b0 Map a1 has start relation to map b1 Map a2 has start relation to map b2 @@ -1499,8 +1520,11 @@ def build_spatio_temporal_topology_list( >>> for map in resultlist: ... if map.get_during(): ... relations = map.get_during() - ... print("Map %s has during relation to map %s"%(map.get_name(), - ... relations[0].get_name())) + ... print( + ... "Map %s has during relation to map %s" + ... % (map.get_name(), relations[0].get_name()) + ... ) + ... Map a0 has during relation to map b0 Map a1 has during relation to map b0 Map a2 has during relation to map b1 @@ -1515,10 +1539,10 @@ def build_spatio_temporal_topology_list( >>> mapsA = [] >>> mapsB = [] >>> for i in range(10): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) ... mapA.uid = idA - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... mapB.uid = idB ... check = mapA.set_relative_time(i, i + 1, "months") @@ -1526,35 +1550,43 @@ def build_spatio_temporal_topology_list( ... mapB.map_value = True ... mapsA.append(mapA) ... mapsB.append(mapB) + ... >>> # Create two list of maps with equal time stamps >>> mapsA = [] >>> mapsB = [] >>> for i in range(10): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) ... mapA.uid = idA ... mapA.map_value = True - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... mapB.uid = idB ... mapB.map_value = False - ... check = mapA.set_absolute_time(datetime(2000,1,i+1), - ... datetime(2000,1,i + 2)) - ... check = mapB.set_absolute_time(datetime(2000,1,i+6), - ... datetime(2000,1,i + 7)) + ... check = mapA.set_absolute_time( + ... datetime(2000, 1, i + 1), datetime(2000, 1, i + 2) + ... ) + ... check = mapB.set_absolute_time( + ... datetime(2000, 1, i + 6), datetime(2000, 1, i + 7) + ... ) ... mapsA.append(mapA) ... mapsB.append(mapB) + ... >>> resultlist = l.build_spatio_temporal_topology_list(mapsA, mapsB) >>> for map in resultlist: ... print(map.get_id()) + ... a5@B a6@B a7@B a8@B a9@B - >>> resultlist = l.build_spatio_temporal_topology_list(mapsA, mapsB, ['during']) + >>> resultlist = l.build_spatio_temporal_topology_list( + ... mapsA, mapsB, ["during"] + ... ) >>> for map in resultlist: ... print(map.get_id()) + ... """ # Check the topology definitions and return the list of temporal and spatial @@ -1678,7 +1710,8 @@ def compare_bool_value( temporal_relations = map_i.get_temporal_relations() - # Build conditional list with elements from related maps and given relation operator. + # Build conditional list with elements from related maps and given relation + # operator. leftbool = map_i.condition_value[0] condition_value_list = [leftbool] count = 0 @@ -1737,7 +1770,7 @@ def eval_toperator(self, operator, optype="relation"): >>> tgis.init() >>> p = tgis.TemporalOperatorParser() >>> operator = "{+, during}" - >>> p.parse(operator, optype = 'raster') + >>> p.parse(operator, optype="raster") >>> print((p.relations, p.temporal, p.function)) (['during'], 'l', '+') @@ -1776,33 +1809,41 @@ def perform_temporal_selection( >>> mapsA = [] >>> mapsB = [] >>> for i in range(10): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) ... mapA.uid = idA - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... mapB.uid = idB ... check = mapA.set_relative_time(i, i + 1, "months") ... check = mapB.set_relative_time(i + 5, i + 6, "months") ... mapsA.append(mapA) ... mapsB.append(mapB) - >>> resultlist = l.perform_temporal_selection(mapsA, mapsB, ['EQUAL'], - ... False) + ... + >>> resultlist = l.perform_temporal_selection( + ... mapsA, mapsB, ["EQUAL"], False + ... ) >>> for map in resultlist: ... if map.get_equal(): ... relations = map.get_equal() - ... print("Map %s has equal relation to map %s"%(map.get_name(), - ... relations[0].get_name())) + ... print( + ... "Map %s has equal relation to map %s" + ... % (map.get_name(), relations[0].get_name()) + ... ) + ... Map a5 has equal relation to map b0 Map a6 has equal relation to map b1 Map a7 has equal relation to map b2 Map a8 has equal relation to map b3 Map a9 has equal relation to map b4 - >>> resultlist = l.perform_temporal_selection(mapsA, mapsB, ['EQUAL'], - ... True) + >>> resultlist = l.perform_temporal_selection(mapsA, mapsB, ["EQUAL"], True) >>> for map in resultlist: ... if not map.get_equal(): - ... print("Map %s has no equal relation to mapset mapsB"%(map.get_name())) + ... print( + ... "Map %s has no equal relation to mapset mapsB" + ... % (map.get_name()) + ... ) + ... Map a0 has no equal relation to mapset mapsB Map a1 has no equal relation to mapset mapsB Map a2 has no equal relation to mapset mapsB @@ -1852,20 +1893,26 @@ def set_granularity(self, maplistA, maplistB, toperator="l", topolist=["EQUAL"]) >>> mapsA = [] >>> mapsB = [] >>> for i in range(10): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) ... mapA.uid = idA - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... mapB.uid = idB ... check = mapA.set_relative_time(i, i + 1, "months") - ... check = mapB.set_relative_time(i*2, i*2 + 2, "months") + ... check = mapB.set_relative_time(i * 2, i * 2 + 2, "months") ... mapsA.append(mapA) ... mapsB.append(mapB) - >>> resultlist = p.set_granularity(mapsA, mapsB, toperator = "u", topolist = ["during"]) + ... + >>> resultlist = p.set_granularity( + ... mapsA, mapsB, toperator="u", topolist=["during"] + ... ) >>> for map in resultlist: - ... start,end,unit = map.get_relative_time() - ... print(map.get_id() + ' - start: ' + str(start) + ' end: ' + str(end)) + ... start, end, unit = map.get_relative_time() + ... print( + ... map.get_id() + " - start: " + str(start) + " end: " + str(end) + ... ) + ... a1@B - start: 0 end: 2 a0@B - start: 0 end: 2 a3@B - start: 2 end: 4 @@ -1933,7 +1980,8 @@ def set_granularity(self, maplistA, maplistB, toperator="l", topolist=["EQUAL"]) if newextent is not None: start = newextent.get_start_time() end = newextent.get_end_time() - # print(map_i.get_id() + ' - start: ' + str(start) + ' end: ' + str(end)) + # print(map_i.get_id() + " - start: " + str(start) + # + " end: " + str(end)) # Track changes in temporal extents of maps. if map_start != start or map_end != end: unchanged = False @@ -1982,12 +2030,14 @@ def get_temporal_func_dict(self, map): >>> # Example with one list of maps >>> # Create one list of maps with equal time stamps >>> for i in range(1): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) ... mapA.uid = idA - ... check = mapA.set_absolute_time(datetime.datetime(2000,1,1), - ... datetime.datetime(2000,10,1)) + ... check = mapA.set_absolute_time( + ... datetime.datetime(2000, 1, 1), datetime.datetime(2000, 10, 1) + ... ) ... tfuncdict = l.get_temporal_func_dict(mapA) + ... >>> print(tfuncdict["START_YEAR"]) 2000 >>> print(tfuncdict["START_TIME"]) @@ -2161,16 +2211,16 @@ def eval_map_list(self, maplist, thenlist, topolist=["EQUAL"]): def build_condition_list(self, tvarexpr, thenlist, topolist=["EQUAL"]): """This function evaluates temporal variable expressions of a conditional expression in two steps. - At first it combines stepwise the single conditions by their relations with LALR. - In this process sub condition map lists will be created which will include - information of the underlying single conditions. Important: The temporal - relations between conditions are evaluated by implicit aggregation. + At first it combines stepwise the single conditions by their relations with + LALR. In this process sub condition map lists will be created which will + include information of the underlying single conditions. Important: The + temporal relations between conditions are evaluated by implicit aggregation. In the second step the aggregated condition map list will be compared with the map list of conclusion statements by the given temporal relation. - The result is written as 'condition_value' attribute to the resulting map objects. - These attribute consists of boolean expressions and operators which can be - evaluated with the eval_condition_list function. + The result is written as 'condition_value' attribute to the resulting map + objects. These attribute consists of boolean expressions and operators which + can be evaluated with the eval_condition_list function. [True, '||', False, '&&', True] For example: td(A) == 1 && start_day() > 5 --> [True || False] @@ -2315,7 +2365,8 @@ def recurse_compare(conditionlist): def p_statement_assign(self, t): # The expression should always return a list of maps - # This function starts all the work and is the last one that is called from the parser + # This function starts all the work and is the last one that is called from the + # parser """ statement : stds EQUALS expr @@ -2353,8 +2404,8 @@ def p_statement_assign(self, t): if maps_stds_type != self.stdstype: self.msgr.warning( _( - "The resulting space time dataset type <%(a)s> is " - "different from the requested type <%(b)s>" + "The resulting space time dataset type <%(a)s> " + "is different from the requested type <%(b)s>" % ({"a": maps_stds_type, "b": self.stdstype}) ) ) @@ -2364,7 +2415,8 @@ def p_statement_assign(self, t): self.msgr.fatal( _( "Maps that should be registered in the " - "resulting space time dataset have different types." + "resulting space time dataset have different " + "types." ) ) count += 1 @@ -2490,7 +2542,8 @@ def p_statement_assign(self, t): if self.dry_run is False: map_i.update_all(dbif) elif map_i.is_in_db(dbif) and self.overwrite is False: - # Raise error if map exists and no overwrite flag is given. + # Raise error if map exists and no overwrite flag is + # given. self.msgr.fatal( "Error map %s exist in temporal database. " "Use overwrite flag." % map_i.get_map_id() @@ -2669,14 +2722,16 @@ def p_expr_tmerge_function(self, t): elif len(maplistA) == 0: self.msgr.message( _( - "First Map list is empty, can't merge it. Return only last map list" + "First Map list is empty, can't merge it. " + "Return only last map list" ) ) resultlist = maplistB elif len(maplistB) == 0: self.msgr.message( _( - "Second Map list is empty, can't merge it. Return only first map list" + "Second Map list is empty, can't merge it. " + "Return only first map list" ) ) resultlist = maplistA @@ -2688,7 +2743,8 @@ def p_expr_tmerge_function(self, t): if typeA != typeB: raise FatalError( _( - "Space time datasets to merge must have the same temporal type" + "Space time datasets to merge must have " + "the same temporal type" ) ) @@ -2832,7 +2888,8 @@ def p_t_var_expr_td_hash(self, t): map_i.condition_value = boolname except: self.msgr.fatal( - "Error: the given expression does not contain a correct time difference object." + "Error: the given expression does not contain a correct time " + "difference object." ) t[0] = maplist @@ -3028,10 +3085,13 @@ def p_expr_t_select_operator(self, t): # Examples: # A {!:} B # Select the part of A that is temporally unequal to B # A { :} B # Select the part of A that is temporally equal B - # A {!:, equals} B # Select the part of A that is temporally unequal to B - # A {!:, during} B # Select the part of A that is temporally not during B + # A {!:, equals} B # Select the part of A that is temporally unequal + # # to B + # A {!:, during} B # Select the part of A that is temporally not + # # during B # A {:, overlaps} B # Select the part of A that temporally overlaps B - # A {:, overlaps|equals} B # Select the part of A that temporally overlaps or equals B + # A {:, overlaps|equals} B # Select the part of A that temporally overlaps + # # or equals B """ expr : stds T_SELECT_OPERATOR stds | expr T_SELECT_OPERATOR stds @@ -3164,7 +3224,8 @@ def p_expr_condition_elif(self, t): def p_expr_condition_elif_relation(self, t): # Examples - # if({equal}, start_date() < "2005-06-01", if(start_time() < "12:30:00", A:B), A!:B) + # if({equal}, start_date() < "2005-06-01", + # if(start_time() < "12:30:00", A:B), A!:B) # The then and else statement using the same topological relationships. # Feature request: Independent relationships for then and else to conditions. """ @@ -3225,7 +3286,8 @@ def p_expr_condition_elif_relation(self, t): def p_expr_t_buff(self, t): # Examples # buff_t(A : B, "10 minutes") # Select the part of A that is temporally - # equal to B and create a buffer of 10 minutes around + # equal to B and create a buffer of 10 minutes + # around """ expr : BUFF_T LPAREN stds COMMA QUOTE number NAME QUOTE RPAREN | BUFF_T LPAREN expr COMMA QUOTE number NAME QUOTE RPAREN @@ -3366,8 +3428,8 @@ def p_error(self, t): # Handle errors. if t: raise SyntaxError( - "syntax error on line %d, position %i token %s near '%s' expression '%s'" - % (t.lineno, t.lexpos, t.type, t.value, self.expression) + "syntax error on line %d, position %i token %s near '%s' expression " + "'%s'" % (t.lineno, t.lexpos, t.type, t.value, self.expression) ) else: raise SyntaxError("Unexpected syntax error") diff --git a/python/grass/temporal/temporal_extent.py b/python/grass/temporal/temporal_extent.py index 4d033c89102..b3ce5714c3b 100644 --- a/python/grass/temporal/temporal_extent.py +++ b/python/grass/temporal/temporal_extent.py @@ -19,6 +19,7 @@ :authors: Soeren Gebbert """ + from .base import SQLDatabaseInterface ############################################################################### @@ -40,9 +41,12 @@ class TemporalExtent(SQLDatabaseInterface): .. code-block:: python >>> init() - >>> A = TemporalExtent(table="raster_absolute_time", - ... ident="soil@PERMANENT", start_time=datetime(2001, 01, 01), - ... end_time=datetime(2005,01,01) ) + >>> A = TemporalExtent( + ... table="raster_absolute_time", + ... ident="soil@PERMANENT", + ... start_time=datetime(2001, 1, 1), + ... end_time=datetime(2005, 1, 1), + ... ) >>> A.id 'soil@PERMANENT' >>> A.start_time @@ -56,8 +60,12 @@ class TemporalExtent(SQLDatabaseInterface): start_time='2001-01-01 00:00:00' end_time='2005-01-01 00:00:00' >>> # relative time - >>> A = TemporalExtent(table="raster_absolute_time", - ... ident="soil@PERMANENT", start_time=0, end_time=1 ) + >>> A = TemporalExtent( + ... table="raster_absolute_time", + ... ident="soil@PERMANENT", + ... start_time=0, + ... end_time=1, + ... ) >>> A.id 'soil@PERMANENT' >>> A.start_time @@ -92,14 +100,14 @@ def intersect(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=5, end_time=6 ) + >>> A = TemporalExtent(start_time=5, end_time=6) >>> inter = A.intersect(A) >>> inter.print_info() | Start time:................. 5 | End time:................... 6 - >>> A = TemporalExtent(start_time=5, end_time=6 ) - >>> B = TemporalExtent(start_time=5, end_time=7 ) + >>> A = TemporalExtent(start_time=5, end_time=6) + >>> B = TemporalExtent(start_time=5, end_time=7) >>> inter = A.intersect(B) >>> inter.print_info() | Start time:................. 5 @@ -109,8 +117,8 @@ def intersect(self, extent): | Start time:................. 5 | End time:................... 6 - >>> A = TemporalExtent(start_time=3, end_time=6 ) - >>> B = TemporalExtent(start_time=5, end_time=7 ) + >>> A = TemporalExtent(start_time=3, end_time=6) + >>> B = TemporalExtent(start_time=5, end_time=7) >>> inter = A.intersect(B) >>> inter.print_info() | Start time:................. 5 @@ -120,8 +128,8 @@ def intersect(self, extent): | Start time:................. 5 | End time:................... 6 - >>> A = TemporalExtent(start_time=3, end_time=8 ) - >>> B = TemporalExtent(start_time=5, end_time=6 ) + >>> A = TemporalExtent(start_time=3, end_time=8) + >>> B = TemporalExtent(start_time=5, end_time=6) >>> inter = A.intersect(B) >>> inter.print_info() | Start time:................. 5 @@ -131,8 +139,8 @@ def intersect(self, extent): | Start time:................. 5 | End time:................... 6 - >>> A = TemporalExtent(start_time=5, end_time=8 ) - >>> B = TemporalExtent(start_time=3, end_time=6 ) + >>> A = TemporalExtent(start_time=5, end_time=8) + >>> B = TemporalExtent(start_time=3, end_time=6) >>> inter = A.intersect(B) >>> inter.print_info() | Start time:................. 5 @@ -142,8 +150,8 @@ def intersect(self, extent): | Start time:................. 5 | End time:................... 6 - >>> A = TemporalExtent(start_time=5, end_time=None ) - >>> B = TemporalExtent(start_time=3, end_time=6 ) + >>> A = TemporalExtent(start_time=5, end_time=None) + >>> B = TemporalExtent(start_time=3, end_time=6) >>> inter = A.intersect(B) >>> inter.print_info() | Start time:................. 5 @@ -153,14 +161,14 @@ def intersect(self, extent): | Start time:................. 5 | End time:................... None - >>> A = TemporalExtent(start_time=5, end_time=8 ) - >>> B = TemporalExtent(start_time=3, end_time=4 ) + >>> A = TemporalExtent(start_time=5, end_time=8) + >>> B = TemporalExtent(start_time=3, end_time=4) >>> inter = A.intersect(B) >>> print(inter) None - >>> A = TemporalExtent(start_time=5, end_time=8 ) - >>> B = TemporalExtent(start_time=3, end_time=None ) + >>> A = TemporalExtent(start_time=5, end_time=8) + >>> B = TemporalExtent(start_time=3, end_time=None) >>> inter = A.intersect(B) >>> print(inter) None @@ -210,14 +218,14 @@ def disjoint_union(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=5, end_time=6 ) + >>> A = TemporalExtent(start_time=5, end_time=6) >>> inter = A.intersect(A) >>> inter.print_info() | Start time:................. 5 | End time:................... 6 - >>> A = TemporalExtent(start_time=5, end_time=6 ) - >>> B = TemporalExtent(start_time=5, end_time=7 ) + >>> A = TemporalExtent(start_time=5, end_time=6) + >>> B = TemporalExtent(start_time=5, end_time=7) >>> inter = A.disjoint_union(B) >>> inter.print_info() | Start time:................. 5 @@ -227,8 +235,8 @@ def disjoint_union(self, extent): | Start time:................. 5 | End time:................... 7 - >>> A = TemporalExtent(start_time=3, end_time=6 ) - >>> B = TemporalExtent(start_time=5, end_time=7 ) + >>> A = TemporalExtent(start_time=3, end_time=6) + >>> B = TemporalExtent(start_time=5, end_time=7) >>> inter = A.disjoint_union(B) >>> inter.print_info() | Start time:................. 3 @@ -238,8 +246,8 @@ def disjoint_union(self, extent): | Start time:................. 3 | End time:................... 7 - >>> A = TemporalExtent(start_time=3, end_time=8 ) - >>> B = TemporalExtent(start_time=5, end_time=6 ) + >>> A = TemporalExtent(start_time=3, end_time=8) + >>> B = TemporalExtent(start_time=5, end_time=6) >>> inter = A.disjoint_union(B) >>> inter.print_info() | Start time:................. 3 @@ -249,8 +257,8 @@ def disjoint_union(self, extent): | Start time:................. 3 | End time:................... 8 - >>> A = TemporalExtent(start_time=5, end_time=8 ) - >>> B = TemporalExtent(start_time=3, end_time=6 ) + >>> A = TemporalExtent(start_time=5, end_time=8) + >>> B = TemporalExtent(start_time=3, end_time=6) >>> inter = A.disjoint_union(B) >>> inter.print_info() | Start time:................. 3 @@ -260,8 +268,8 @@ def disjoint_union(self, extent): | Start time:................. 3 | End time:................... 8 - >>> A = TemporalExtent(start_time=5, end_time=None ) - >>> B = TemporalExtent(start_time=3, end_time=6 ) + >>> A = TemporalExtent(start_time=5, end_time=None) + >>> B = TemporalExtent(start_time=3, end_time=6) >>> inter = A.disjoint_union(B) >>> inter.print_info() | Start time:................. 3 @@ -271,8 +279,8 @@ def disjoint_union(self, extent): | Start time:................. 3 | End time:................... 6 - >>> A = TemporalExtent(start_time=5, end_time=8 ) - >>> B = TemporalExtent(start_time=3, end_time=4 ) + >>> A = TemporalExtent(start_time=5, end_time=8) + >>> B = TemporalExtent(start_time=3, end_time=4) >>> inter = A.disjoint_union(B) >>> inter.print_info() | Start time:................. 3 @@ -281,8 +289,8 @@ def disjoint_union(self, extent): >>> inter.print_info() | Start time:................. 3 | End time:................... 8 - >>> A = TemporalExtent(start_time=5, end_time=8 ) - >>> B = TemporalExtent(start_time=3, end_time=None ) + >>> A = TemporalExtent(start_time=5, end_time=8) + >>> B = TemporalExtent(start_time=3, end_time=None) >>> inter = A.disjoint_union(B) >>> inter.print_info() | Start time:................. 3 @@ -291,8 +299,8 @@ def disjoint_union(self, extent): >>> inter.print_info() | Start time:................. 3 | End time:................... 8 - >>> A = TemporalExtent(start_time=5, end_time=None ) - >>> B = TemporalExtent(start_time=3, end_time=8 ) + >>> A = TemporalExtent(start_time=5, end_time=None) + >>> B = TemporalExtent(start_time=3, end_time=8) >>> inter = A.disjoint_union(B) >>> inter.print_info() | Start time:................. 3 @@ -301,8 +309,8 @@ def disjoint_union(self, extent): >>> inter.print_info() | Start time:................. 3 | End time:................... 8 - >>> A = TemporalExtent(start_time=5, end_time=None ) - >>> B = TemporalExtent(start_time=3, end_time=None ) + >>> A = TemporalExtent(start_time=5, end_time=None) + >>> B = TemporalExtent(start_time=3, end_time=None) >>> inter = A.disjoint_union(B) >>> inter.print_info() | Start time:................. 3 @@ -312,8 +320,8 @@ def disjoint_union(self, extent): | Start time:................. 3 | End time:................... 5 - >>> A = RelativeTemporalExtent(start_time=5, end_time=None, unit="years" ) - >>> B = RelativeTemporalExtent(start_time=3, end_time=None, unit="years" ) + >>> A = RelativeTemporalExtent(start_time=5, end_time=None, unit="years") + >>> B = RelativeTemporalExtent(start_time=3, end_time=None, unit="years") >>> inter = A.disjoint_union(B) >>> inter.print_info() +-------------------- Relative time -----------------------------------------+ @@ -330,8 +338,12 @@ def disjoint_union(self, extent): >>> from datetime import datetime as dt - >>> A = AbsoluteTemporalExtent(start_time=dt(2001,1,10), end_time=dt(2003,1,1)) - >>> B = AbsoluteTemporalExtent(start_time=dt(2005,1,10), end_time=dt(2008,1,1)) + >>> A = AbsoluteTemporalExtent( + ... start_time=dt(2001, 1, 10), end_time=dt(2003, 1, 1) + ... ) + >>> B = AbsoluteTemporalExtent( + ... start_time=dt(2005, 1, 10), end_time=dt(2008, 1, 1) + ... ) >>> inter = A.disjoint_union(B) >>> inter.print_info() +-------------------- Absolute time -----------------------------------------+ @@ -344,7 +356,7 @@ def disjoint_union(self, extent): | Start time:................. 2001-01-10 00:00:00 | End time:................... 2008-01-01 00:00:00 - """ + """ # noqa: E501 start = None end = None @@ -395,14 +407,14 @@ def union(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=5, end_time=8 ) - >>> B = TemporalExtent(start_time=3, end_time=4 ) + >>> A = TemporalExtent(start_time=5, end_time=8) + >>> B = TemporalExtent(start_time=3, end_time=4) >>> inter = A.intersect(B) >>> print(inter) None - >>> A = TemporalExtent(start_time=5, end_time=8 ) - >>> B = TemporalExtent(start_time=3, end_time=None ) + >>> A = TemporalExtent(start_time=5, end_time=8) + >>> B = TemporalExtent(start_time=3, end_time=None) >>> inter = A.intersect(B) >>> print(inter) None @@ -432,8 +444,8 @@ def starts(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=5, end_time=6 ) - >>> B = TemporalExtent(start_time=5, end_time=7 ) + >>> A = TemporalExtent(start_time=5, end_time=6) + >>> B = TemporalExtent(start_time=5, end_time=7) >>> A.starts(B) True >>> B.starts(A) @@ -466,8 +478,8 @@ def started(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=5, end_time=7 ) - >>> B = TemporalExtent(start_time=5, end_time=6 ) + >>> A = TemporalExtent(start_time=5, end_time=7) + >>> B = TemporalExtent(start_time=5, end_time=6) >>> A.started(B) True >>> B.started(A) @@ -500,8 +512,8 @@ def finishes(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=6, end_time=7 ) - >>> B = TemporalExtent(start_time=5, end_time=7 ) + >>> A = TemporalExtent(start_time=6, end_time=7) + >>> B = TemporalExtent(start_time=5, end_time=7) >>> A.finishes(B) True >>> B.finishes(A) @@ -534,8 +546,8 @@ def finished(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=5, end_time=7 ) - >>> B = TemporalExtent(start_time=6, end_time=7 ) + >>> A = TemporalExtent(start_time=5, end_time=7) + >>> B = TemporalExtent(start_time=6, end_time=7) >>> A.finished(B) True >>> B.finished(A) @@ -568,8 +580,8 @@ def after(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=8, end_time=9 ) - >>> B = TemporalExtent(start_time=6, end_time=7 ) + >>> A = TemporalExtent(start_time=8, end_time=9) + >>> B = TemporalExtent(start_time=6, end_time=7) >>> A.after(B) True >>> B.after(A) @@ -602,8 +614,8 @@ def before(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=6, end_time=7 ) - >>> B = TemporalExtent(start_time=8, end_time=9 ) + >>> A = TemporalExtent(start_time=6, end_time=7) + >>> B = TemporalExtent(start_time=8, end_time=9) >>> A.before(B) True >>> B.before(A) @@ -638,14 +650,14 @@ def adjacent(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=5, end_time=7 ) - >>> B = TemporalExtent(start_time=7, end_time=9 ) + >>> A = TemporalExtent(start_time=5, end_time=7) + >>> B = TemporalExtent(start_time=7, end_time=9) >>> A.adjacent(B) True >>> B.adjacent(A) True - >>> A = TemporalExtent(start_time=5, end_time=7 ) - >>> B = TemporalExtent(start_time=3, end_time=5 ) + >>> A = TemporalExtent(start_time=5, end_time=7) + >>> B = TemporalExtent(start_time=3, end_time=5) >>> A.adjacent(B) True >>> B.adjacent(A) @@ -677,8 +689,8 @@ def follows(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=5, end_time=7 ) - >>> B = TemporalExtent(start_time=3, end_time=5 ) + >>> A = TemporalExtent(start_time=5, end_time=7) + >>> B = TemporalExtent(start_time=3, end_time=5) >>> A.follows(B) True >>> B.follows(A) @@ -709,8 +721,8 @@ def precedes(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=5, end_time=7 ) - >>> B = TemporalExtent(start_time=7, end_time=9 ) + >>> A = TemporalExtent(start_time=5, end_time=7) + >>> B = TemporalExtent(start_time=7, end_time=9) >>> A.precedes(B) True >>> B.precedes(A) @@ -740,8 +752,8 @@ def during(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=5, end_time=7 ) - >>> B = TemporalExtent(start_time=4, end_time=9 ) + >>> A = TemporalExtent(start_time=5, end_time=7) + >>> B = TemporalExtent(start_time=4, end_time=9) >>> A.during(B) True >>> B.during(A) @@ -785,8 +797,8 @@ def contains(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=4, end_time=9 ) - >>> B = TemporalExtent(start_time=5, end_time=8 ) + >>> A = TemporalExtent(start_time=4, end_time=9) + >>> B = TemporalExtent(start_time=5, end_time=8) >>> A.contains(B) True >>> B.contains(A) @@ -830,8 +842,8 @@ def equal(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=5, end_time=6 ) - >>> B = TemporalExtent(start_time=5, end_time=6 ) + >>> A = TemporalExtent(start_time=5, end_time=6) + >>> B = TemporalExtent(start_time=5, end_time=6) >>> A.equal(B) True >>> B.equal(A) @@ -870,15 +882,15 @@ def overlaps(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=5, end_time=7 ) - >>> B = TemporalExtent(start_time=6, end_time=8 ) + >>> A = TemporalExtent(start_time=5, end_time=7) + >>> B = TemporalExtent(start_time=6, end_time=8) >>> A.overlaps(B) True >>> B.overlaps(A) False - >>> A = TemporalExtent(start_time=5, end_time=6 ) - >>> B = TemporalExtent(start_time=6, end_time=8 ) + >>> A = TemporalExtent(start_time=5, end_time=6) + >>> B = TemporalExtent(start_time=6, end_time=8) >>> A.overlaps(B) False >>> B.overlaps(A) @@ -913,15 +925,15 @@ def overlapped(self, extent): .. code-block:: python - >>> A = TemporalExtent(start_time=6, end_time=8 ) - >>> B = TemporalExtent(start_time=5, end_time=7 ) + >>> A = TemporalExtent(start_time=6, end_time=8) + >>> B = TemporalExtent(start_time=5, end_time=7) >>> A.overlapped(B) True >>> B.overlapped(A) False - >>> A = TemporalExtent(start_time=6, end_time=8 ) - >>> B = TemporalExtent(start_time=5, end_time=6 ) + >>> A = TemporalExtent(start_time=6, end_time=8) + >>> B = TemporalExtent(start_time=5, end_time=6) >>> A.overlapped(B) False >>> B.overlapped(A) @@ -1078,7 +1090,7 @@ def print_info(self): """Print information about this class in human readable style""" # 0123456789012345678901234567890 print( - " +-------------------- Absolute time -----------------------------------------+" + " +-------------------- Absolute time -----------------------------------------+" # noqa: E501 ) TemporalExtent.print_info(self) @@ -1125,10 +1137,14 @@ class STDSAbsoluteTime(AbsoluteTemporalExtent): .. code-block:: python >>> init() - >>> A = STDSAbsoluteTime(table="strds_absolute_time", - ... ident="strds@PERMANENT", start_time=datetime(2001, 01, 01), - ... end_time=datetime(2005,01,01), granularity="1 days", - ... map_time="interval") + >>> A = STDSAbsoluteTime( + ... table="strds_absolute_time", + ... ident="strds@PERMANENT", + ... start_time=datetime(2001, 1, 1), + ... end_time=datetime(2005, 1, 1), + ... granularity="1 days", + ... map_time="interval", + ... ) >>> A.id 'strds@PERMANENT' >>> A.start_time @@ -1263,8 +1279,13 @@ class RelativeTemporalExtent(TemporalExtent): .. code-block:: python >>> init() - >>> A = RelativeTemporalExtent(table="raster_relative_time", - ... ident="soil@PERMANENT", start_time=0, end_time=1, unit="years") + >>> A = RelativeTemporalExtent( + ... table="raster_relative_time", + ... ident="soil@PERMANENT", + ... start_time=0, + ... end_time=1, + ... unit="years", + ... ) >>> A.id 'soil@PERMANENT' >>> A.start_time @@ -1336,7 +1357,7 @@ def print_info(self): """Print information about this class in human readable style""" # 0123456789012345678901234567890 print( - " +-------------------- Relative time -----------------------------------------+" + " +-------------------- Relative time -----------------------------------------+" # noqa: E501 ) TemporalExtent.print_info(self) print(" | Relative time unit:......... " + str(self.get_unit())) @@ -1384,9 +1405,15 @@ class STDSRelativeTime(RelativeTemporalExtent): .. code-block:: python >>> init() - >>> A = STDSRelativeTime(table="strds_relative_time", - ... ident="strds@PERMANENT", start_time=0, end_time=1, unit="years", - ... granularity=5, map_time="interval") + >>> A = STDSRelativeTime( + ... table="strds_relative_time", + ... ident="strds@PERMANENT", + ... start_time=0, + ... end_time=1, + ... unit="years", + ... granularity=5, + ... map_time="interval", + ... ) >>> A.id 'strds@PERMANENT' >>> A.start_time diff --git a/python/grass/temporal/temporal_granularity.py b/python/grass/temporal/temporal_granularity.py index df7eb949b0f..3b1b005d533 100644 --- a/python/grass/temporal/temporal_granularity.py +++ b/python/grass/temporal/temporal_granularity.py @@ -17,6 +17,7 @@ :authors: Soeren Gebbert """ + from .datetime_math import compute_datetime_delta from .abstract_map_dataset import AbstractMapDataset from functools import reduce @@ -204,94 +205,102 @@ def compute_relative_time_granularity(maps): >>> tgis.init() >>> maps = [] >>> for i in range(5): - ... map = tgis.RasterDataset("a%i@P"%i) - ... check = map.set_relative_time(i,i + 1,"seconds") - ... if check: - ... maps.append(map) + ... map = tgis.RasterDataset("a%i@P" % i) + ... check = map.set_relative_time(i, i + 1, "seconds") + ... if check: + ... maps.append(map) + ... >>> tgis.compute_relative_time_granularity(maps) 1 >>> maps = [] >>> count = 0 - >>> timelist = ((0,3), (3,6), (6,9)) + >>> timelist = ((0, 3), (3, 6), (6, 9)) >>> for t in timelist: - ... map = tgis.RasterDataset("a%i@P"%count) - ... check = map.set_relative_time(t[0],t[1],"years") - ... if check: - ... maps.append(map) - ... count += 1 + ... map = tgis.RasterDataset("a%i@P" % count) + ... check = map.set_relative_time(t[0], t[1], "years") + ... if check: + ... maps.append(map) + ... count += 1 + ... >>> tgis.compute_relative_time_granularity(maps) 3 >>> maps = [] >>> count = 0 - >>> timelist = ((0,3), (4,6), (8,11)) + >>> timelist = ((0, 3), (4, 6), (8, 11)) >>> for t in timelist: - ... map = tgis.RasterDataset("a%i@P"%count) - ... check = map.set_relative_time(t[0],t[1],"years") - ... if check: - ... maps.append(map) - ... count += 1 + ... map = tgis.RasterDataset("a%i@P" % count) + ... check = map.set_relative_time(t[0], t[1], "years") + ... if check: + ... maps.append(map) + ... count += 1 + ... >>> tgis.compute_relative_time_granularity(maps) 1 >>> maps = [] >>> count = 0 - >>> timelist = ((0,8), (2,6), (5,9)) + >>> timelist = ((0, 8), (2, 6), (5, 9)) >>> for t in timelist: - ... map = tgis.RasterDataset("a%i@P"%count) - ... check = map.set_relative_time(t[0],t[1],"months") - ... if check: - ... maps.append(map) - ... count += 1 + ... map = tgis.RasterDataset("a%i@P" % count) + ... check = map.set_relative_time(t[0], t[1], "months") + ... if check: + ... maps.append(map) + ... count += 1 + ... >>> tgis.compute_relative_time_granularity(maps) 4 >>> maps = [] >>> count = 0 - >>> timelist = ((0,8), (8,12), (12,18)) + >>> timelist = ((0, 8), (8, 12), (12, 18)) >>> for t in timelist: - ... map = tgis.RasterDataset("a%i@P"%count) - ... check = map.set_relative_time(t[0],t[1],"days") - ... if check: - ... maps.append(map) - ... count += 1 + ... map = tgis.RasterDataset("a%i@P" % count) + ... check = map.set_relative_time(t[0], t[1], "days") + ... if check: + ... maps.append(map) + ... count += 1 + ... >>> tgis.compute_relative_time_granularity(maps) 2 >>> maps = [] >>> count = 0 - >>> timelist = ((0,None), (8,None), (12,None), (24,None)) + >>> timelist = ((0, None), (8, None), (12, None), (24, None)) >>> for t in timelist: - ... map = tgis.RasterDataset("a%i@P"%count) - ... check = map.set_relative_time(t[0],t[1],"minutes") - ... if check: - ... maps.append(map) - ... count += 1 + ... map = tgis.RasterDataset("a%i@P" % count) + ... check = map.set_relative_time(t[0], t[1], "minutes") + ... if check: + ... maps.append(map) + ... count += 1 + ... >>> tgis.compute_relative_time_granularity(maps) 4 >>> maps = [] >>> count = 0 - >>> timelist = ((0,None), (8,14), (18,None), (24,None)) + >>> timelist = ((0, None), (8, 14), (18, None), (24, None)) >>> for t in timelist: - ... map = tgis.RasterDataset("a%i@P"%count) - ... check = map.set_relative_time(t[0],t[1],"hours") - ... if check: - ... maps.append(map) - ... count += 1 + ... map = tgis.RasterDataset("a%i@P" % count) + ... check = map.set_relative_time(t[0], t[1], "hours") + ... if check: + ... maps.append(map) + ... count += 1 + ... >>> tgis.compute_relative_time_granularity(maps) 2 >>> maps = [] >>> count = 0 - >>> timelist = ((0,21),) + >>> timelist = ((0, 21),) >>> for t in timelist: - ... map = tgis.RasterDataset("a%i@P"%count) - ... check = map.set_relative_time(t[0],t[1],"hours") - ... if check: - ... maps.append(map) - ... count += 1 + ... map = tgis.RasterDataset("a%i@P" % count) + ... check = map.set_relative_time(t[0], t[1], "hours") + ... if check: + ... maps.append(map) + ... count += 1 + ... >>> tgis.compute_relative_time_granularity(maps) 21 @@ -363,61 +372,77 @@ def compute_absolute_time_granularity(maps): >>> tgis.init() >>> maps = [] >>> count = 0 - >>> timelist = ((dt(2000,01,01),None), (dt(2000,02,01),None)) + >>> timelist = ((dt(2000, 1, 1), None), (dt(2000, 2, 1), None)) >>> for t in timelist: - ... map = tgis.RasterDataset("a%i@P"%count) - ... check = map.set_absolute_time(t[0],t[1]) - ... if check: - ... maps.append(map) - ... count += 1 + ... map = tgis.RasterDataset("a%i@P" % count) + ... check = map.set_absolute_time(t[0], t[1]) + ... if check: + ... maps.append(map) + ... count += 1 + ... >>> tgis.compute_absolute_time_granularity(maps) '1 month' >>> maps = [] >>> count = 0 - >>> timelist = ((dt(2000,01,01),None), (dt(2000,01,02),None), (dt(2000,01,03),None)) + >>> timelist = ( + ... (dt(2000, 1, 1), None), + ... (dt(2000, 1, 2), None), + ... (dt(2000, 1, 3), None), + ... ) >>> for t in timelist: - ... map = tgis.RasterDataset("a%i@P"%count) - ... check = map.set_absolute_time(t[0],t[1]) - ... if check: - ... maps.append(map) - ... count += 1 + ... map = tgis.RasterDataset("a%i@P" % count) + ... check = map.set_absolute_time(t[0], t[1]) + ... if check: + ... maps.append(map) + ... count += 1 + ... >>> tgis.compute_absolute_time_granularity(maps) '1 day' >>> maps = [] >>> count = 0 - >>> timelist = ((dt(2000,01,01),None), (dt(2000,01,02),None), (dt(2000,05,04,0,5,30),None)) + >>> timelist = ( + ... (dt(2000, 1, 1), None), + ... (dt(2000, 1, 2), None), + ... (dt(2000, 5, 4, 0, 5, 30), None), + ... ) >>> for t in timelist: - ... map = tgis.RasterDataset("a%i@P"%count) - ... check = map.set_absolute_time(t[0],t[1]) - ... if check: - ... maps.append(map) - ... count += 1 + ... map = tgis.RasterDataset("a%i@P" % count) + ... check = map.set_absolute_time(t[0], t[1]) + ... if check: + ... maps.append(map) + ... count += 1 + ... >>> tgis.compute_absolute_time_granularity(maps) '30 seconds' >>> maps = [] >>> count = 0 - >>> timelist = ((dt(2000,01,01),dt(2000,05,02)), (dt(2000,05,04,2),None)) + >>> timelist = ((dt(2000, 1, 1), dt(2000, 5, 2)), (dt(2000, 5, 4, 2), None)) >>> for t in timelist: - ... map = tgis.RasterDataset("a%i@P"%count) - ... check = map.set_absolute_time(t[0],t[1]) - ... if check: - ... maps.append(map) - ... count += 1 + ... map = tgis.RasterDataset("a%i@P" % count) + ... check = map.set_absolute_time(t[0], t[1]) + ... if check: + ... maps.append(map) + ... count += 1 + ... >>> tgis.compute_absolute_time_granularity(maps) '2 hours' >>> maps = [] >>> count = 0 - >>> timelist = ((dt(2000,01,01),dt(2000,02,01)), (dt(2005,05,04,12),dt(2007,05,20,6))) + >>> timelist = ( + ... (dt(2000, 1, 1), dt(2000, 2, 1)), + ... (dt(2005, 5, 4, 12), dt(2007, 5, 20, 6)), + ... ) >>> for t in timelist: - ... map = tgis.RasterDataset("a%i@P"%count) - ... check = map.set_absolute_time(t[0],t[1]) - ... if check: - ... maps.append(map) - ... count += 1 + ... map = tgis.RasterDataset("a%i@P" % count) + ... check = map.set_absolute_time(t[0], t[1]) + ... if check: + ... maps.append(map) + ... count += 1 + ... >>> tgis.compute_absolute_time_granularity(maps) '6 hours' @@ -537,13 +562,13 @@ def compute_common_relative_time_granularity(gran_list): >>> import grass.temporal as tgis >>> tgis.init() - >>> grans = [1,2,30] + >>> grans = [1, 2, 30] >>> tgis.compute_common_relative_time_granularity(grans) 1 >>> import grass.temporal as tgis >>> tgis.init() - >>> grans = [10,20,30] + >>> grans = [10, 20, 30] >>> tgis.compute_common_relative_time_granularity(grans) 10 """ @@ -572,130 +597,168 @@ def compute_common_absolute_time_granularity(gran_list, start_date_list=None): >>> import grass.temporal as tgis >>> tgis.init() >>> grans = ["20 second", "10 minutes", "2 hours"] - >>> dates = [datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '20 seconds' >>> grans = ["20 second", "10 minutes", "2 hours"] - >>> dates = [datetime(2001,1,1,0,0,20), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 0, 20), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '1 second' >>> grans = ["7200 second", "240 minutes", "1 year"] - >>> dates = [datetime(2001,1,1,0,0,10), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 0, 10), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '1 second' >>> grans = ["7200 second", "89 minutes", "1 year"] - >>> dates = [datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '60 seconds' >>> grans = ["120 minutes", "2 hours"] - >>> dates = [datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '60 minutes' >>> grans = ["120 minutes", "2 hours"] - >>> dates = [datetime(2001,1,1,0,30,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 30, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '1 minute' >>> grans = ["360 minutes", "3 hours"] - >>> dates = [datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '60 minutes' >>> grans = ["2 hours", "4 hours", "8 hours"] - >>> dates = [datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '2 hours' >>> grans = ["2 hours", "4 hours", "8 hours"] - >>> dates = [datetime(2001,1,1,2,0,0), - ... datetime(2001,1,1,4,0,0), - ... datetime(2001,1,1,8,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 2, 0, 0), + ... datetime(2001, 1, 1, 4, 0, 0), + ... datetime(2001, 1, 1, 8, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '1 hour' >>> grans = ["8 hours", "2 days"] - >>> dates = [datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '8 hours' >>> grans = ["8 hours", "2 days"] - >>> dates = [datetime(2001,1,1,10,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 10, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '1 hour' >>> grans = ["120 months", "360 months", "4 years"] - >>> dates = [datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '12 months' >>> grans = ["30 days", "10 days", "5 days"] - >>> dates = [datetime(2001,2,1,0,0,0), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 2, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '5 days' >>> grans = ["30 days", "10 days", "5 days"] - >>> dates = [datetime(2001,2,2,0,0,0), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 2, 2, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '1 day' >>> grans = ["2 days", "360 months", "4 years"] - >>> dates = [datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '2 days' >>> grans = ["2 days", "360 months", "4 years"] - >>> dates = [datetime(2001,1,2,0,0,0), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 2, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '1 day' >>> grans = ["120 months", "360 months", "4 years"] - >>> dates = [datetime(2001,2,1,0,0,0), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 2, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '1 month' >>> grans = ["120 months", "361 months", "4 years"] - >>> dates = [datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '1 month' >>> grans = ["120 months", "360 months", "4 years"] - >>> dates = [datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0), - ... datetime(2001,1,1,0,0,0),] + >>> dates = [ + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... datetime(2001, 1, 1, 0, 0, 0), + ... ] >>> tgis.compute_common_absolute_time_granularity(grans, dates) '12 months' @@ -1055,16 +1118,16 @@ def gran_singular_unit(gran): >>> import grass.temporal as tgis >>> tgis.init() - >>> tgis.gran_singular_unit('1 month') + >>> tgis.gran_singular_unit("1 month") 'month' - >>> tgis.gran_singular_unit('2 months') + >>> tgis.gran_singular_unit("2 months") 'month' - >>> tgis.gran_singular_unit('6 seconds') + >>> tgis.gran_singular_unit("6 seconds") 'second' - >>> tgis.gran_singular_unit('1 year') + >>> tgis.gran_singular_unit("1 year") 'year' """ if check_granularity_string(gran, "absolute"): @@ -1100,16 +1163,16 @@ def gran_plural_unit(gran): >>> import grass.temporal as tgis >>> tgis.init() - >>> tgis.gran_singular_unit('1 month') + >>> tgis.gran_singular_unit("1 month") 'month' - >>> tgis.gran_singular_unit('2 months') + >>> tgis.gran_singular_unit("2 months") 'month' - >>> tgis.gran_singular_unit('6 seconds') + >>> tgis.gran_singular_unit("6 seconds") 'second' - >>> tgis.gran_singular_unit('1 year') + >>> tgis.gran_singular_unit("1 year") 'year' """ if check_granularity_string(gran, "absolute"): @@ -1148,28 +1211,28 @@ def gran_to_gran(from_gran, to_gran="days", shell=False): >>> import grass.temporal as tgis >>> tgis.init() - >>> tgis.gran_to_gran('1 month', '1 day') + >>> tgis.gran_to_gran("1 month", "1 day") '30.436875 days' - >>> tgis.gran_to_gran('1 month', '1 day', True) + >>> tgis.gran_to_gran("1 month", "1 day", True) 30.436875 - >>> tgis.gran_to_gran('10 year', '1 hour') + >>> tgis.gran_to_gran("10 year", "1 hour") '87658.2 hours' - >>> tgis.gran_to_gran('10 year', '1 minute') + >>> tgis.gran_to_gran("10 year", "1 minute") '5259492.0 minutes' - >>> tgis.gran_to_gran('6 months', '1 day') + >>> tgis.gran_to_gran("6 months", "1 day") '182.62125 days' - >>> tgis.gran_to_gran('1 months', '1 second') + >>> tgis.gran_to_gran("1 months", "1 second") '2629746.0 seconds' - >>> tgis.gran_to_gran('1 month', '1 second', True) + >>> tgis.gran_to_gran("1 month", "1 second", True) 2629746.0 - >>> tgis.gran_to_gran('30 month', '1 month', True) + >>> tgis.gran_to_gran("30 month", "1 month", True) 30 """ diff --git a/python/grass/temporal/temporal_operator.py b/python/grass/temporal/temporal_operator.py index f2a5a57bb1c..0bf001ee0c5 100644 --- a/python/grass/temporal/temporal_operator.py +++ b/python/grass/temporal/temporal_operator.py @@ -12,133 +12,134 @@ .. code-block:: python >>> p = TemporalOperatorParser() - >>> expression = "{equal|equivalent|cover|in|meet|contain|overlap}" - >>> p.parse(expression, optype = 'relation') + >>> expression = "{equal|equivalent|cover|in|meet|contain|overlap}" + >>> p.parse(expression, optype="relation") >>> print((p.relations, p.temporal, p.function)) (['equal', 'equivalent', 'cover', 'in', 'meet', 'contain', 'overlap'], None, None) >>> p = TemporalOperatorParser() - >>> expression = "{equal| during}" - >>> p.parse(expression, optype = 'relation') + >>> expression = "{equal| during}" + >>> p.parse(expression, optype="relation") >>> print((p.relations, p.temporal, p.function)) (['equal', 'during'], None, None) >>> p = TemporalOperatorParser() - >>> expression = "{contains | starts}" + >>> expression = "{contains | starts}" >>> p.parse(expression) >>> print((p.relations, p.temporal, p.function)) (['contains', 'starts'], None, None) >>> p = TemporalOperatorParser() - >>> expression = "{&&, during}" - >>> p.parse(expression, optype = 'boolean') + >>> expression = "{&&, during}" + >>> p.parse(expression, optype="boolean") >>> print((p.relations, p.temporal, p.function, p.aggregate)) (['during'], 'l', '&&', '&') >>> p = TemporalOperatorParser() - >>> expression = "{||, equal | during}" - >>> p.parse(expression, optype = 'boolean') + >>> expression = "{||, equal | during}" + >>> p.parse(expression, optype="boolean") >>> print((p.relations, p.temporal, p.function, p.aggregate)) (['equal', 'during'], 'l', '||', '|') >>> p = TemporalOperatorParser() - >>> expression = "{||, equal | during, &}" - >>> p.parse(expression, optype = 'boolean') + >>> expression = "{||, equal | during, &}" + >>> p.parse(expression, optype="boolean") >>> print((p.relations, p.temporal, p.function, p.aggregate)) (['equal', 'during'], 'l', '||', '&') >>> p = TemporalOperatorParser() - >>> expression = "{&&, during, |}" - >>> p.parse(expression, optype = 'boolean') + >>> expression = "{&&, during, |}" + >>> p.parse(expression, optype="boolean") >>> print((p.relations, p.temporal, p.function, p.aggregate)) (['during'], 'l', '&&', '|') >>> p = TemporalOperatorParser() - >>> expression = "{&&, during, |, r}" - >>> p.parse(expression, optype = 'boolean') + >>> expression = "{&&, during, |, r}" + >>> p.parse(expression, optype="boolean") >>> print((p.relations, p.temporal, p.function, p.aggregate)) (['during'], 'r', '&&', '|') >>> p = TemporalOperatorParser() - >>> expression = "{&&, during, u}" - >>> p.parse(expression, optype = 'boolean') + >>> expression = "{&&, during, u}" + >>> p.parse(expression, optype="boolean") >>> print((p.relations, p.temporal, p.function, p.aggregate)) (['during'], 'u', '&&', '&') >>> p = TemporalOperatorParser() - >>> expression = "{:, during, r}" - >>> p.parse(expression, optype = 'select') + >>> expression = "{:, during, r}" + >>> p.parse(expression, optype="select") >>> print((p.relations, p.temporal, p.function)) (['during'], 'r', ':') >>> p = TemporalOperatorParser() - >>> expression = "{!:, equal | contains, d}" - >>> p.parse(expression, optype = 'select') + >>> expression = "{!:, equal | contains, d}" + >>> p.parse(expression, optype="select") >>> print((p.relations, p.temporal, p.function)) (['equal', 'contains'], 'd', '!:') >>> p = TemporalOperatorParser() - >>> expression = "{#, during, r}" - >>> p.parse(expression, optype = 'hash') + >>> expression = "{#, during, r}" + >>> p.parse(expression, optype="hash") >>> print((p.relations, p.temporal, p.function)) (['during'], 'r', '#') >>> p = TemporalOperatorParser() - >>> expression = "{#, equal | contains}" - >>> p.parse(expression, optype = 'hash') + >>> expression = "{#, equal | contains}" + >>> p.parse(expression, optype="hash") >>> print((p.relations, p.temporal, p.function)) (['equal', 'contains'], 'l', '#') >>> p = TemporalOperatorParser() - >>> expression = "{+, during, r}" - >>> p.parse(expression, optype = 'raster') + >>> expression = "{+, during, r}" + >>> p.parse(expression, optype="raster") >>> print((p.relations, p.temporal, p.function)) (['during'], 'r', '+') >>> p = TemporalOperatorParser() - >>> expression = "{/, equal | contains}" - >>> p.parse(expression, optype = 'raster') + >>> expression = "{/, equal | contains}" + >>> p.parse(expression, optype="raster") >>> print((p.relations, p.temporal, p.function)) (['equal', 'contains'], 'l', '/') >>> p = TemporalOperatorParser() - >>> expression = "{+, equal | contains,intersect}" - >>> p.parse(expression, optype = 'raster') + >>> expression = "{+, equal | contains,intersect}" + >>> p.parse(expression, optype="raster") >>> print((p.relations, p.temporal, p.function)) (['equal', 'contains'], 'i', '+') >>> p = TemporalOperatorParser() - >>> expression = "{*, contains,disjoint}" - >>> p.parse(expression, optype = 'raster') + >>> expression = "{*, contains,disjoint}" + >>> p.parse(expression, optype="raster") >>> print((p.relations, p.temporal, p.function)) (['contains'], 'd', '*') >>> p = TemporalOperatorParser() - >>> expression = "{~, equal,left}" - >>> p.parse(expression, optype = 'overlay') + >>> expression = "{~, equal,left}" + >>> p.parse(expression, optype="overlay") >>> print((p.relations, p.temporal, p.function)) (['equal'], 'l', '~') >>> p = TemporalOperatorParser() - >>> expression = "{^, over,right}" - >>> p.parse(expression, optype = 'overlay') + >>> expression = "{^, over,right}" + >>> p.parse(expression, optype="overlay") >>> print((p.relations, p.temporal, p.function)) (['overlaps', 'overlapped'], 'r', '^') >>> p = TemporalOperatorParser() - >>> expression = "{&&, equal | during | contains | starts, &}" - >>> p.parse(expression, optype = 'boolean') + >>> expression = "{&&, equal | during | contains | starts, &}" + >>> p.parse(expression, optype="boolean") >>> print((p.relations, p.temporal, p.function, p.aggregate)) (['equal', 'during', 'contains', 'starts'], 'l', '&&', '&') >>> p = TemporalOperatorParser() - >>> expression = "{&&, equal | during | contains | starts, &&&&&}" - >>> p.parse(expression, optype = 'boolean') + >>> expression = "{&&, equal | during | contains | starts, &&&&&}" + >>> p.parse(expression, optype="boolean") Traceback (most recent call last): SyntaxError: Unexpected syntax error in expression "{&&, equal | during | contains | starts, &&&&&}" at position 42 near & >>> p = TemporalOperatorParser() - >>> expression = "{+, starting}" + >>> expression = "{+, starting}" >>> p.parse(expression) Traceback (most recent call last): SyntaxError: syntax error on line 1 position 4 near 'starting' >>> p = TemporalOperatorParser() - >>> expression = "{nope, start, |, l}" + >>> expression = "{nope, start, |, l}" >>> p.parse(expression) Traceback (most recent call last): SyntaxError: syntax error on line 1 position 1 near 'nope' >>> p = TemporalOperatorParser() - >>> expression = "{++, start, |, l}" + >>> expression = "{++, start, |, l}" >>> p.parse(expression) Traceback (most recent call last): SyntaxError: Unexpected syntax error in expression "{++, start, |, l}" at position 2 near + >>> p = TemporalOperatorParser() - >>> expression = "{^, over, right}" - >>> p.parse(expression, optype='rter') + >>> expression = "{^, over, right}" + >>> p.parse(expression, optype="rter") Traceback (most recent call last): SyntaxError: Unknown optype rter, must be one of ['select', 'boolean', 'raster', 'hash', 'relation', 'overlay'] -""" +""" # noqa: E501 + try: import ply.lex as lex import ply.yacc as yacc diff --git a/python/grass/temporal/temporal_raster3d_algebra.py b/python/grass/temporal/temporal_raster3d_algebra.py index 536f035130c..88d44768b6a 100644 --- a/python/grass/temporal/temporal_raster3d_algebra.py +++ b/python/grass/temporal/temporal_raster3d_algebra.py @@ -10,6 +10,7 @@ :authors: Thomas Leppelt and Soeren Gebbert """ + try: import ply.yacc as yacc except ImportError: diff --git a/python/grass/temporal/temporal_raster_base_algebra.py b/python/grass/temporal/temporal_raster_base_algebra.py index 12daadf2f3b..dfae8f86863 100644 --- a/python/grass/temporal/temporal_raster_base_algebra.py +++ b/python/grass/temporal/temporal_raster_base_algebra.py @@ -14,7 +14,7 @@ >>> p = TemporalRasterAlgebraLexer() >>> p.build() >>> p.debug = True - >>> expression = 'R = A {+,equal,l} B' + >>> expression = "R = A {+,equal,l} B" >>> p.test(expression) R = A {+,equal,l} B LexToken(NAME,'R',1,0) @@ -22,7 +22,7 @@ LexToken(NAME,'A',1,4) LexToken(T_ARITH2_OPERATOR,'{+,equal,l}',1,6) LexToken(NAME,'B',1,18) - >>> expression = 'R = A {*,equal|during,r} B' + >>> expression = "R = A {*,equal|during,r} B" >>> p.test(expression) R = A {*,equal|during,r} B LexToken(NAME,'R',1,0) @@ -30,7 +30,7 @@ LexToken(NAME,'A',1,4) LexToken(T_ARITH1_OPERATOR,'{*,equal|during,r}',1,6) LexToken(NAME,'B',1,25) - >>> expression = 'R = A {+,equal|during} B' + >>> expression = "R = A {+,equal|during} B" >>> p.test(expression) R = A {+,equal|during} B LexToken(NAME,'R',1,0) @@ -40,6 +40,7 @@ LexToken(NAME,'B',1,23) """ + import copy import grass.pygrass.modules as pymod @@ -118,7 +119,7 @@ def __init__(self): t_MULT = r"[\*]" t_ADD = r"[\+]" t_SUB = r"[-]" - t_T_ARITH1_OPERATOR = r"\{[\%\*\/][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}" + t_T_ARITH1_OPERATOR = r"\{[\%\*\/][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}" # noqa: E501 t_T_ARITH2_OPERATOR = ( r"\{[+-][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}" ) @@ -244,23 +245,27 @@ def build_spatio_temporal_topology_list( >>> mapsA = [] >>> mapsB = [] >>> for i in range(10): - ... idA = "a%i@B"%(i) + ... idA = "a%i@B" % (i) ... mapA = tgis.RasterDataset(idA) ... mapA.uid = idA ... mapA.map_value = True - ... idB = "b%i@B"%(i) + ... idB = "b%i@B" % (i) ... mapB = tgis.RasterDataset(idB) ... mapB.uid = idB ... mapB.map_value = False - ... check = mapA.set_absolute_time(datetime(2000,1,i+1), - ... datetime(2000,1,i + 2)) - ... check = mapB.set_absolute_time(datetime(2000,1,i+6), - ... datetime(2000,1,i + 7)) + ... check = mapA.set_absolute_time( + ... datetime(2000, 1, i + 1), datetime(2000, 1, i + 2) + ... ) + ... check = mapB.set_absolute_time( + ... datetime(2000, 1, i + 6), datetime(2000, 1, i + 7) + ... ) ... mapsA.append(mapA) ... mapsB.append(mapB) + ... >>> resultlist = l.build_spatio_temporal_topology_list(mapsA, mapsB) >>> for map in resultlist: ... print(map.get_id()) + ... a5@B a6@B a7@B @@ -440,7 +445,8 @@ def compare_cmd_value( :return: Map object with conditional value that has been evaluated by comparison operators. """ - # Build command list list with elements from related maps and given relation operator. + # Build command list list with elements from related maps and given relation + # operator. if convert and "condition_value" in dir(map_i): if map_i.condition_value != []: cmdstring = str(int(map_i.condition_value[0])) @@ -508,7 +514,8 @@ def operator_cmd_value( temporal_relations = map_i.get_temporal_relations() spatial_relations = map_i.get_spatial_relations() - # Build comandlist list with elements from related maps and given relation operator. + # Build comandlist list with elements from related maps and given relation + # operator. leftcmd = map_i cmdstring = "" for topo in temporal_topo_list: @@ -576,7 +583,8 @@ def set_temporal_extent_list( base_map=map_i, bool_op="and", copy=True, rename=True ) - # Combine temporal and spatial extents of intermediate map with related maps. + # Combine temporal and spatial extents of intermediate map with related + # maps. for topo in topolist: if topo in tbrelations.keys(): for map_j in tbrelations[topo]: @@ -599,7 +607,8 @@ def set_temporal_extent_list( map_new, map_j, "and", temp_op=temporal ) - # Stop the loop if no temporal or spatial relationship exist. + # Stop the loop if no temporal or spatial relationship + # exist. if returncode == 0: break # Append map to result map list. @@ -607,7 +616,8 @@ def set_temporal_extent_list( # print(map_new.cmd_list) # resultlist.append(map_new) if cmd_bool: - # Create r.mapcalc expression string for the operation. + # Create r.mapcalc expression string for the + # operation. cmdstring = self.build_command_string( map_i, map_j, @@ -643,8 +653,10 @@ def build_condition_cmd_list( For Example: 'if(a1 == 1, b1, c2)' :param iflist: Map list with temporal extents and command list. - :param thenlist: Map list with temporal extents and command list or numeric string. - :param elselist: Map list with temporal extents and command list or numeric string. + :param thenlist: Map list with temporal extents and command list or numeric + string. + :param elselist: Map list with temporal extents and command list or numeric + string. :param condition_topolist: List of strings for given temporal relations between conditions and conclusions. :param conclusion_topolist: List of strings for given temporal relations between @@ -1783,7 +1795,7 @@ def p_s_numeric_condition_elif(self, t): | IF LPAREN ts_var_expr COMMA NULL LPAREN RPAREN COMMA number RPAREN | IF LPAREN ts_var_expr COMMA number COMMA NULL LPAREN RPAREN RPAREN | IF LPAREN ts_var_expr COMMA NULL LPAREN RPAREN COMMA NULL LPAREN RPAREN RPAREN - """ + """ # noqa: E501 ifmaplist = self.check_stds(t[3]) # Select input for r.mapcalc expression based on length of PLY object. if len(t) == 9: @@ -1894,7 +1906,7 @@ def p_s_numeric_expr_condition_elif_relation(self, t): | IF LPAREN T_REL_OPERATOR COMMA ts_var_expr COMMA stds COMMA NULL LPAREN RPAREN RPAREN | IF LPAREN T_REL_OPERATOR COMMA ts_var_expr COMMA expr COMMA number RPAREN | IF LPAREN T_REL_OPERATOR COMMA ts_var_expr COMMA expr COMMA NULL LPAREN RPAREN RPAREN - """ + """ # noqa: E501 relations, temporal, function, aggregation = self.eval_toperator( t[3], optype="relation" ) diff --git a/python/grass/temporal/temporal_topology_dataset_connector.py b/python/grass/temporal/temporal_topology_dataset_connector.py index 4a105bee033..fddf478ad71 100644 --- a/python/grass/temporal/temporal_topology_dataset_connector.py +++ b/python/grass/temporal/temporal_topology_dataset_connector.py @@ -15,6 +15,7 @@ :authors: Soeren Gebbert """ + import copy @@ -55,6 +56,8 @@ class TemporalTopologyDatasetConnector: start = start.next() + .. code-block:: python + >>> import grass.temporal as tgis >>> tgis.init() >>> map = tgis.RasterDataset("a@P") @@ -103,7 +106,8 @@ class TemporalTopologyDatasetConnector: finished=a@P >>> rlist = tmr.get_temporal_relations() >>> if "FINISHED" in rlist.keys(): - ... print(rlist["FINISHED"][0].get_id()) + ... print(rlist["FINISHED"][0].get_id()) + ... a@P """ @@ -503,7 +507,7 @@ def print_temporal_topology_info(self): """Print information about this class in human readable style""" print( - " +-------------------- Temporal Topology -------------------------------------+" + " +-------------------- Temporal Topology -------------------------------------+" # noqa: E501 ) # 0123456789012345678901234567890 if self.next() is not None: diff --git a/python/grass/temporal/temporal_vector_algebra.py b/python/grass/temporal/temporal_vector_algebra.py index 5e545e08574..7b3f838d461 100644 --- a/python/grass/temporal/temporal_vector_algebra.py +++ b/python/grass/temporal/temporal_vector_algebra.py @@ -16,7 +16,7 @@ >>> p = tgis.TemporalVectorAlgebraLexer() >>> p.build() >>> p.debug = True - >>> expression = 'E = A : B ^ C : D' + >>> expression = "E = A : B ^ C : D" >>> p.test(expression) E = A : B ^ C : D LexToken(NAME,'E',1,0) @@ -28,7 +28,7 @@ LexToken(NAME,'C',1,12) LexToken(T_SELECT,':',1,14) LexToken(NAME,'D',1,16) - >>> expression = 'E = buff_a(A, 10)' + >>> expression = "E = buff_a(A, 10)" >>> p.test(expression) E = buff_a(A, 10) LexToken(NAME,'E',1,0) @@ -41,6 +41,7 @@ LexToken(RPAREN,')',1,16) """ + try: import ply.yacc as yacc except ImportError: @@ -94,7 +95,7 @@ def __init__(self): t_XOR = r"\^" t_NOT = r"\~" # t_T_OVERLAY_OPERATOR = r'\{([a-zA-Z\|]+[,])?([\|&+=]?[\|&+=\^\~])\}' - t_T_OVERLAY_OPERATOR = r"\{[\|&+\^\~][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}" + t_T_OVERLAY_OPERATOR = r"\{[\|&+\^\~][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}" # noqa: E501 # Parse symbols def temporal_symbol(self, t): @@ -304,7 +305,8 @@ def overlay_cmd_value(self, map_i, tbrelations, function, topolist=["EQUAL"]): :return: Map object with command list with operators that has been evaluated by implicit aggregration. """ - # Build comandlist list with elements from related maps and given relation operator. + # Build comandlist list with elements from related maps and given relation + # operator. resultlist = [] # Define overlay operation dictionary. overlaydict = {"&": "and", "|": "or", "^": "xor", "~": "not", "+": "disor"} @@ -377,7 +379,7 @@ def set_temporal_extent_list(self, maplist, topolist=["EQUAL"], temporal="l"): map_new = self.generate_new_map( base_map=map_i, bool_op="and", copy=True, rename=False, remove=True ) - # Combine temporal and spatial extents of intermediate map with related maps. + # Combine temporal and spatial extents of intermediate map with related maps for topo in topolist: if topo in tbrelations.keys(): for map_j in tbrelations[topo]: @@ -444,20 +446,22 @@ def p_statement_assign(self, t): # Execute command list. for cmd in map_i.cmd_list: try: - # We need to check if the input maps have areas in case of v.overlay - # otherwise v.overlay will break + # We need to check if the input maps have areas in case + # of v.overlay. Otherwise v.overlay will break. if cmd.name == "v.overlay": for name in ( cmd.inputs["ainput"].value, cmd.inputs["binput"].value, ): - # self.msgr.message("Check if map <" + name + "> exists") + # self.msgr.message("Check if map <" + name + + # "> exists") if name.find("@") < 0: name = name + "@" + get_current_mapset() tmp_map = map_i.get_new_instance(name) if not tmp_map.map_exists(): raise Exception - # self.msgr.message("Check if map <" + name + "> has areas") + # self.msgr.message("Check if map <" + name + + # "> has areas") tmp_map.load() if tmp_map.metadata.get_number_of_areas() == 0: raise Exception @@ -501,7 +505,8 @@ def p_statement_assign(self, t): register_list.append(map_i) else: # Test if temporal extents have been changed by temporal - # relation operators (i|r). This is a code copy from temporal_algebra.py + # relation operators (i|r). This is a code copy from + # temporal_algebra.py map_i_extent = map_i.get_temporal_extent_as_tuple() map_test = map_i.get_new_instance(map_i.get_id()) map_test.select(dbif) @@ -556,11 +561,12 @@ def p_statement_assign(self, t): # Update map in temporal database. map_i.update_all(dbif=dbif) elif map_i.is_in_db(dbif=dbif) and self.overwrite is False: - # Raise error if map exists and no overwrite flag is given. + # Raise error if map exists and no overwrite flag is + # given. self.msgr.fatal( _( - "Error vector map %s exist in temporal database. " - "Use overwrite flag. : \n%s" + "Error vector map %s exist in temporal " + "database. Use overwrite flag. : \n%s" ) % (map_i.get_map_id(), cmd.outputs.stderr) ) diff --git a/python/grass/temporal/testsuite/test_register_function.py b/python/grass/temporal/testsuite/test_register_function.py index fcf1ad756bf..923e4034027 100644 --- a/python/grass/temporal/testsuite/test_register_function.py +++ b/python/grass/temporal/testsuite/test_register_function.py @@ -24,7 +24,7 @@ def setUpClass(cls): os.putenv("GRASS_OVERWRITE", "1") # Use always the current mapset as temporal database cls.runModule("g.gisenv", set="TGIS_USE_CURRENT_MAPSET=1") - tgis.init() + cls.dbif = tgis.init() cls.use_temp_region() cls.runModule("g.region", n=80.0, s=0.0, e=120.0, w=0.0, t=1.0, b=0.0, res=10.0) @@ -72,7 +72,7 @@ def tearDown(self): self.runModule( "t.unregister", type="raster", - maps="register_map_1,register_map_2", + maps="register_map_1,register_map_2,elevation", quiet=True, ) self.runModule( @@ -118,7 +118,8 @@ def test_absolute_time_strds_1(self): def test_absolute_time_strds_2(self): """Test the registration of maps with absolute time in a space time raster dataset. - The timestamps are set using the C-Interface beforehand, so that the register function needs + The timestamps are set using the C-Interface beforehand, + so that the register function needs to read the timetsamp from the map metadata. """ @@ -155,9 +156,10 @@ def test_absolute_time_strds_2(self): def test_absolute_time_strds_3(self): """Test the registration of maps with absolute time in a - space time raster dataset. The timestamps are set via method arguments and with the - c-interface. The timestamps of the method arguments should overwrite the - time stamps set via the C-interface. + space time raster dataset. The timestamps are set via method + arguments and with the c-interface. The timestamps of the + method arguments should overwrite the time stamps set via the + C-interface. """ ciface = tgis.get_tgis_c_library_interface() @@ -187,9 +189,10 @@ def test_absolute_time_strds_3(self): def test_absolute_time_strds_4(self): """Test the registration of maps with absolute time in a - space time raster dataset. The timestamps are set via method arguments and with the - c-interface. The timestamps of the method arguments should overwrite the - time stamps set via the C-interface. The C-interface sets relative time stamps. + space time raster dataset. The timestamps are set via method + arguments and with the c-interface. The timestamps of the method + arguments should overwrite the time stamps set via the C-interface. + The C-interface sets relative time stamps. """ ciface = tgis.get_tgis_c_library_interface() @@ -258,7 +261,8 @@ def test_absolute_time_1(self): def test_absolute_time_2(self): """Test the registration of maps with absolute time - using register_maps_in_space_time_dataset() and register_map_object_list() with empty map deletion + using register_maps_in_space_time_dataset() and + register_map_object_list() with empty map deletion """ tgis.register_maps_in_space_time_dataset( type="raster", @@ -300,9 +304,58 @@ def test_absolute_time_2(self): map_3 = tgis.VectorDataset("register_map_null@" + tgis.get_current_mapset()) self.assertEqual(map_3.map_exists(), False) + def test_history_raster(self): + """Test that raster maps are registered with the history + (creator and creation time) of the raster map itself (and from a + different mapset (PERMANENT) + """ + tgis.register_maps_in_space_time_dataset( + type="raster", + name=None, + maps="elevation@PERMANENT", + start="2001-01-01 10:30:01", + increment="1 year", + interval=True, + dbif=self.dbif, + ) + + map_1 = tgis.RasterDataset("elevation@PERMANENT") + map_1.select(self.dbif, tgis.get_current_mapset()) + # Test that creation time of the map is used + self.assertEqual( + map_1.base.get_ctime(), datetime.datetime(2006, 11, 7, 1, 9, 51) + ) + # Test that registered creator of the map is not the current user + self.assertEqual(map_1.base.get_creator(), "helena") + + def test_history_vector(self): + """Test that vector maps are registered with the history (creator + and creation time) of the vector map itself (and from a + different mapset (PERMANENT) + """ + tgis.register_maps_in_space_time_dataset( + type="vector", + name=None, + maps="lakes@PERMANENT", + start="2001-01-01 10:30:01", + increment="1 year", + interval=True, + dbif=self.dbif, + ) + + map_1 = tgis.VectorDataset("lakes@PERMANENT") + map_1.select(self.dbif, tgis.get_current_mapset()) + # Test that creation time of the map is used + self.assertEqual( + map_1.base.get_ctime(), datetime.datetime(2006, 11, 7, 19, 48, 8) + ) + # Test that registered creator of the map is not the current user + self.assertTrue(map_1.base.get_creator(), "helena") + def test_absolute_time_3(self): """Test the registration of maps with absolute time. - The timestamps are set using the C-Interface beforehand, so that the register function needs + The timestamps are set using the C-Interface beforehand, + so that the register function needs to read the timetsamp from the map metadata. """ @@ -365,8 +418,8 @@ def test_relative_time_strds_1(self): def test_relative_time_strds_2(self): """Test the registration of maps with relative time in a - space time raster dataset. The timetsamps are set for the maps using the - C-interface before registration. + space time raster dataset. The timestamps are set for the maps + using the C-interface before registration. """ ciface = tgis.get_tgis_c_library_interface() ciface.write_raster_timestamp( @@ -459,8 +512,8 @@ def test_relative_time_2(self): self.assertEqual(unit, "seconds") def test_relative_time_3(self): - """Test the registration of maps with relative time. The timetsamps are set beforehand using - the C-interface. + """Test the registration of maps with relative time. The + timestamps are set beforehand using the C-interface. """ ciface = tgis.get_tgis_c_library_interface() ciface.write_raster_timestamp( @@ -619,7 +672,8 @@ def test_absolute_time_stvds_1(self): def test_absolute_time_stvds_2(self): """Test the registration of maps with absolute time in a space time raster dataset. - The timestamps are set using the C-Interface beforehand, so that the register function needs + The timestamps are set using the C-Interface beforehand, + so that the register function needs to read the timetsamp from the map metadata. """ @@ -656,9 +710,9 @@ def test_absolute_time_stvds_2(self): def test_absolute_time_stvds_3(self): """Test the registration of maps with absolute time in a - space time raster dataset. The timestamps are set via method arguments and with the - c-interface. The timestamps of the method arguments should overwrite the - time stamps set via the C-interface. + space time raster dataset. The timestamps are set via method + arguments and with the C-interface. The timestamps of the method + arguments should overwrite the time stamps set via the C-interface. """ ciface = tgis.get_tgis_c_library_interface() @@ -687,7 +741,8 @@ def test_absolute_time_stvds_3(self): self.assertEqual(end, datetime.datetime(2001, 2, 2)) def test_absolute_time_1(self): - """Register vector maps in the temporal database and in addition in a stvds using the object method + """Register vector maps in the temporal database and in addition + in a stvds using the object method :return: """ diff --git a/python/grass/temporal/testsuite/unittests_temporal_raster3d_algebra.py b/python/grass/temporal/testsuite/unittests_temporal_raster3d_algebra.py index fd011a55d53..1ed80cd1316 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_raster3d_algebra.py +++ b/python/grass/temporal/testsuite/unittests_temporal_raster3d_algebra.py @@ -7,7 +7,6 @@ :authors: Soeren Gebbert and Thomas Leppelt """ - import grass.script import grass.temporal as tgis from grass.gunittest.case import TestCase diff --git a/python/grass/temporal/unit_tests.py b/python/grass/temporal/unit_tests.py index fd412ee6cf2..8083680ef3f 100644 --- a/python/grass/temporal/unit_tests.py +++ b/python/grass/temporal/unit_tests.py @@ -8,6 +8,7 @@ :authors: Soeren Gebbert """ + import copy from datetime import datetime import grass.script.core as core diff --git a/python/grass/temporal/univar_statistics.py b/python/grass/temporal/univar_statistics.py index 80cca737199..5ae6f255d1b 100755 --- a/python/grass/temporal/univar_statistics.py +++ b/python/grass/temporal/univar_statistics.py @@ -7,7 +7,9 @@ import grass.temporal as tgis - tgis.print_gridded_dataset_univar_statistics(type, input, output, where, extended, no_header, fs, rast_region) + tgis.print_gridded_dataset_univar_statistics( + type, input, output, where, extended, no_header, fs, rast_region + ) .. @@ -18,6 +20,7 @@ :authors: Soeren Gebbert """ + from multiprocessing import Pool from subprocess import PIPE @@ -32,10 +35,12 @@ def compute_univar_stats(registered_map_info, stats_module, fs, rast_region=False): - """Compute univariate statistics for a map of a space time raster or raster3d dataset + """Compute univariate statistics for a map of a space time raster or raster3d + dataset :param registered_map_info: dict or db row with tgis info for a registered map - :param stats_module: Pre-configured PyGRASS Module to compute univariate statistics with + :param stats_module: Pre-configured PyGRASS Module to compute univariate statistics + with :param fs: Field separator :param rast_region: If set True ignore the current region settings and use the raster map regions for univar statistical calculation. @@ -100,7 +105,8 @@ def compute_univar_stats(registered_map_info, stats_module, fs, rast_region=Fals if stats_module.inputs.percentile: for perc in stats_module.inputs.percentile: perc_value = stats[ - f"percentile_{str(perc).rstrip('0').rstrip('.').replace('.','_')}" + "percentile_" + f"{str(perc).rstrip('0').rstrip('.').replace('.','_')}" ] string += f"{fs}{perc_value}" string += eol @@ -216,7 +222,8 @@ def print_gridded_dataset_univar_statistics( if percentile: cols.extend( [ - f"percentile_{str(perc).rstrip('0').rstrip('.').replace('.','_')}" + "percentile_" + f"{str(perc).rstrip('0').rstrip('.').replace('.','_')}" for perc in percentile ] ) diff --git a/python/libgrass_interface_generator/CMakeLists.txt b/python/libgrass_interface_generator/CMakeLists.txt new file mode 100644 index 00000000000..0f3719e25f7 --- /dev/null +++ b/python/libgrass_interface_generator/CMakeLists.txt @@ -0,0 +1,98 @@ +set(MODULES + date + gis + raster + gmath + proj + imagery + vector + rtree + display + stats + dbmi + raster3d + arraystats + cluster + vedit + segment + rowio + temporal) + +if(WITH_OPENGL) + list(APPEND MODULES ogsf nviz) +endif() + +set(date_HDRS datetime.h defs/datetime.h) +set(date_LIBS grass_datetime) +set(date_TARGET_NAME grass_datetime_py) + +set(gis_HDRS gis.h defs/gis.h colors.h defs/colors.h) +set(raster_HDRS raster.h defs/raster.h) +set(gmath_HDRS gmath.h defs/gmath.h) +set(proj_HDRS gprojects.h defs/gprojects.h) +set(proj_LIBS grass_gproj) +set(vector_HDRS vector.h defs/vector.h vect/dig_structs.h vect/dig_defines.h + vect/dig_externs.h) +set(display_HDRS display.h defs/display.h) +set(dbmi_HDRS dbmi.h defs/dbmi.h) +set(dbmi_LIBS grass_dbmibase grass_dbmiclient) +set(arraystats_HDRS arraystats.h defs/arraystats.h) +set(vedit_HDRS vedit.h defs/vedit.h) +set(nviz_HDRS nviz.h defs/nviz.h) +set(rowio_HDRS rowio.h defs/rowio.h) +set(temporal_HDRS temporal.h) +set(ogsf_HDRS ogsf.h defs/ogsf.h) +set(segment_HDRS segment.h defs/segment.h) +set(imagery_HDRS imagery.h defs/imagery.h) +set(rtree_HDRS rtree.h) +set(stats_HDRS stats.h defs/stats.h) +set(raster3d_HDRS raster3d.h defs/raster3d.h) +set(cluster_HDRS cluster.h defs/cluster.h) + +# TODO set(VECT_INC ${PQINCPATH} ) set(proj_INC "${PROJ_INCLUDE_DIR}") +# set(vector_INC "${PQINCPATH};${GDAL_INCLUDE_DIR}") set(vedit_INC +# "${GDAL_INCLUDE_DIR}") + +foreach(module ${MODULES}) + if(NOT ${module}_LIBS) + set(${module}_LIBS grass_${module}) + endif() + + if(NOT ${module}_HDRS) + message(FATAL_ERROR "${module}_HDRS is not set") + endif() + + foreach(${module}_LIB ${${module}_LIBS}) + if(NOT TARGET ${${module}_LIB}) + message(FATAL_ERROR "${${module}_LIB} is not a target") + endif() + endforeach() + + if(NOT ${module}_TARGET_NAME) + list(GET ${module}_LIBS 0 first_lib) + set(${module}_TARGET_NAME ${first_lib}_py) + endif() + + if(NOT ${module}_TARGET_NAME) + message(FATAL_ERROR "${${module}_TARGET_NAME} is not set") + endif() + + set(output_file "${GISBASE}/etc/python/grass/lib/${module}.py") + + add_custom_command( + OUTPUT ${output_file} + DEPENDS ${${module}_LIBS} + COMMAND + ${CMAKE_COMMAND} -DCTYPESGEN_PY=${CMAKE_CURRENT_SOURCE_DIR}/run.py + -DPython_EXECUTABLE=${Python_EXECUTABLE} -DCOMPILER=${CMAKE_C_COMPILER} + -DBIN_DIR=${GISBASE} "-DHDRS=${${module}_HDRS}" "-DLIBS=${${module}_LIBS}" + -DOUT_FILE=${output_file} -DGRASS_VERSION_NUMBER=${GRASS_VERSION_NUMBER} + -P ${CMAKE_SOURCE_DIR}/cmake/ctypesgen.cmake + COMMENT "Generating ${output_file}" + VERBATIM) + + add_custom_target(${${module}_TARGET_NAME} ALL DEPENDS ${output_file}) + set_target_properties(${${module}_TARGET_NAME} PROPERTIES FOLDER lib/python) + install(FILES ${output_file} DESTINATION etc/python/grass/lib) + +endforeach() diff --git a/raster/CMakeLists.txt b/raster/CMakeLists.txt new file mode 100644 index 00000000000..068818d49bd --- /dev/null +++ b/raster/CMakeLists.txt @@ -0,0 +1,410 @@ +build_program_in_subdir(r.basins.fill DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.buildvrt DEPENDS grass_gis grass_raster grass_gmath) + +build_program_in_subdir(r.buffer DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.carve DEPENDS grass_gis grass_raster grass_vector + grass_bitmap) + +build_program_in_subdir(r.category DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.circle DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.clump DEPENDS grass_gis grass_raster grass_btree2) + +build_program_in_subdir(r.coin DEPENDS grass_gis grass_raster) + +add_subdirectory(r.colors) + +add_subdirectory(r.colors.out) + +build_program_in_subdir(r.composite DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.compress DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.contour DEPENDS grass_gis grass_raster grass_vector) + +build_program_in_subdir(r.cost DEPENDS grass_gis grass_raster grass_segment + grass_vector) + +build_program_in_subdir(r.covar DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.cross DEPENDS grass_gis grass_raster grass_btree + grass_btree2) + +build_program_in_subdir(r.describe DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.distance DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.drain DEPENDS grass_gis grass_raster grass_vector) + +build_program_in_subdir(r.external DEPENDS grass_gis grass_raster grass_imagery + grass_gproj) + +build_program_in_subdir(r.external.out DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.fill.dir DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.fill.stats DEPENDS grass_gis grass_raster) + +build_program_in_subdir( + r.flow + DEPENDS + grass_gis + grass_raster + grass_segment + grass_vector + grass_bitmap) + +build_program_in_subdir(r.geomorphon DEPENDS grass_gis grass_raster grass_gmath) + +build_program_in_subdir(r.grow.distance DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.gwflow DEPENDS grass_gis grass_raster grass_gpde) + +build_program_in_subdir(r.his DEPENDS grass_gis grass_raster grass_gproj) + +build_program_in_subdir(r.horizon DEPENDS grass_gis grass_raster grass_gproj + grass_parson) + +build_program_in_subdir(r.in.ascii DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.in.bin DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.in.gdal DEPENDS grass_gis grass_raster grass_gproj + grass_imagery) + +build_program_in_subdir(r.in.gridatb DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.in.mat DEPENDS grass_gis grass_raster) + +file(GLOB r_in_pdal_SOURCES "r.in.pdal/*.c" "r.in.pdal/*.cpp") +build_program_in_subdir( + r.in.pdal + SOURCES + "${r_in_pdal_SOURCES}" + DEPENDS + grass_gis + grass_raster + grass_vector + grass_gmath + grass_segment + grass_gproj + PRIMARY_DEPENDS + PDAL) + +if(WITH_LIBPNG) + build_program_in_subdir(r.in.png DEPENDS grass_gis grass_raster LIBPNG) +endif() + +build_program_in_subdir(r.in.poly DEPENDS grass_gis grass_raster) + +if(NOT MSVC) + build_program_in_subdir(r.in.xyz DEPENDS grass_gis grass_raster) +endif() +build_program_in_subdir(r.info TEST_SOURCES "test_r_info.py" DEPENDS grass_gis + grass_raster) + +build_program_in_subdir(r.kappa DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.latlong DEPENDS grass_gis grass_raster grass_gproj) + +build_program_in_subdir(r.lake DEPENDS grass_gis grass_raster) + +build_program_in_subdir( + r.mfilter + DEPENDS + grass_gis + grass_raster + grass_rowio + OPTIONAL_DEPENDS + OPENMP) + +build_program_in_subdir(r.mode DEPENDS grass_gis grass_raster) + +build_program_in_subdir( + r.neighbors + DEPENDS + grass_gis + grass_raster + grass_stats + OPTIONAL_DEPENDS + OPENMP) + +build_program_in_subdir(r.null DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.object.geometry DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.out.ascii DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.out.bin DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.out.gdal DEPENDS grass_gis grass_raster + grass_dbmibase grass_imagery) + +set_source_files_properties( + r.out.gdal/main.c + PROPERTIES COMPILE_DEFINITIONS + "GRASS_VERSION_NUMBER=\"${GRASS_VERSION_NUMBER}\"") + +build_program_in_subdir(r.out.gridatb DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.out.mat DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.out.mpeg DEPENDS grass_gis grass_raster) + +if(WITH_LIBPNG) + build_program_in_subdir(r.out.png DEPENDS grass_gis grass_raster LIBPNG) +endif() + +build_program_in_subdir(r.out.pov DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.out.ppm DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.out.ppm3 DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.out.vrml DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.out.vtk DEPENDS grass_gis grass_raster) + +build_program_in_subdir( + r.param.scale + DEPENDS + grass_gis + grass_raster + grass_interpfl + grass_interpdata + grass_qtree) + +build_program_in_subdir(r.patch DEPENDS grass_gis grass_raster OPTIONAL_DEPENDS + OPENMP) + +build_program_in_subdir(r.path DEPENDS grass_gis grass_raster grass_vector) + +build_program_in_subdir(r.profile DEPENDS grass_gis grass_raster) + +build_program_in_subdir( + r.proj + DEPENDS + grass_gis + grass_raster + grass_gproj + OPTIONAL_DEPENDS + OPENMP) + +build_program_in_subdir(r.quant DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.quantile DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.random DEPENDS grass_gis grass_raster grass_vector) + +build_program_in_subdir(r.random.cells DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.random.surface DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.reclass DEPENDS grass_gis grass_raster grass_manage) + +build_program_in_subdir(r.recode DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.region DEPENDS grass_gis grass_raster grass_vector) + +build_program_in_subdir(r.regression.line DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.regression.multi DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.report DEPENDS grass_gis grass_raster) + +build_program_in_subdir( + r.resamp.bspline + DEPENDS + grass_gis + grass_raster + grass_vector + grass_segment + grass_lidar) + +build_program_in_subdir(r.resamp.filter DEPENDS grass_gis grass_raster + OPTIONAL_DEPENDS OPENMP) + +build_program_in_subdir(r.resamp.interp DEPENDS grass_gis grass_raster + OPTIONAL_DEPENDS OPENMP) + +build_program_in_subdir( + r.resamp.rst + DEPENDS + grass_gis + grass_raster + grass_interpfl + grass_interpdata + grass_qtree) + +build_program_in_subdir(r.resamp.stats DEPENDS grass_gis grass_raster + grass_stats) + +build_program_in_subdir(r.resample DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.rescale DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.rescale.eq DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.ros DEPENDS grass_gis grass_raster) + +build_program_in_subdir( + r.series + DEPENDS + grass_gis + grass_raster + grass_stats + OPTIONAL_DEPENDS + OPENMP) + +build_program_in_subdir( + r.series.accumulate + DEPENDS + grass_gis + grass_raster + grass_stats + OPTIONAL_DEPENDS + OPENMP) + +build_program_in_subdir(r.series.interp DEPENDS grass_gis grass_raster + grass_stats) + +build_program_in_subdir(r.relief DEPENDS grass_gis grass_raster) + +add_subdirectory(r.sim) + +build_program_in_subdir(r.slope.aspect DEPENDS grass_gis grass_raster + OPTIONAL_DEPENDS OPENMP) + +build_program_in_subdir(r.solute.transport DEPENDS grass_gis grass_raster + grass_gmath grass_gpde) + +add_subdirectory(r.spread) + +build_program_in_subdir(r.spreadpath DEPENDS grass_gis grass_raster + grass_segment) + +build_program_in_subdir(r.statistics DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.stats.zonal DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.stats.quantile DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.stats DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.stream.extract DEPENDS grass_gis grass_raster + grass_segment grass_vector) + +build_program_in_subdir( + r.sun + DEPENDS + grass_gmath + grass_raster + grass_gproj + OPTIONAL_DEPENDS + OPENMP) + +build_program_in_subdir(r.sunhours DEPENDS grass_gis grass_raster grass_gproj) + +build_program_in_subdir(r.sunmask DEPENDS grass_gis grass_raster grass_gproj) + +build_program_in_subdir(r.support DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.support.stats DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.surf.area DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.surf.contour DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.surf.fractal DEPENDS grass_gis grass_raster + grass_gmath) + +build_program_in_subdir(r.surf.gauss DEPENDS grass_gis grass_raster grass_gmath) + +build_program_in_subdir(r.surf.idw DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.surf.random DEPENDS grass_gis grass_raster + grass_gmath) + +if(MSVC) + set(USER_NAME $ENV{USERNAME}) +else() + set(USER_NAME $ENV{USER}) +endif() + +build_program_in_subdir(r.texture DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.thin DEPENDS grass_gis grass_raster grass_rowio) + +build_program_in_subdir(r.tile DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.timestamp DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.to.rast3 DEPENDS grass_gis grass_raster3d) + +build_program_in_subdir(r.to.rast3elev DEPENDS grass_gis grass_raster3d) + +build_program_in_subdir(r.to.vect DEPENDS grass_gis grass_raster grass_vector) + +build_program_in_subdir(r.topidx DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.topmodel DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.transect DEPENDS grass_gis grass_raster) + +add_subdirectory(r.univar) + +build_program_in_subdir(r.uslek DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.usler DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.volume DEPENDS grass_gis grass_raster grass_vector) + +build_program_in_subdir(r.walk DEPENDS grass_gis grass_raster grass_segment + grass_vector) + +build_program_in_subdir(r.water.outlet DEPENDS grass_gis grass_raster) + +build_program_in_subdir(r.what DEPENDS grass_gis grass_raster grass_vector + grass_parson) + +build_program_in_subdir(r.what.color DEPENDS grass_gis grass_raster) + +build_program_in_subdir( + r.in.lidar + DEPENDS + grass_gis + grass_raster + grass_lidar + PRIMARY_DEPENDS + LIBLAS) + +add_subdirectory(r.li) + +add_subdirectory(r.mapcalc) + +build_program_in_subdir( + r.viewshed + DEPENDS + grass_gis + grass_raster + grass_iostream + SRC_REGEX + "*.cpp" + DEFS + "-DUSER=${USER_NAME}") + +build_program_in_subdir( + r.terraflow + DEPENDS + grass_gis + grass_raster + grass_iostream + SRC_REGEX + "*.cpp" + DEFS + "-DUSER=${USER_NAME};-DNODATA_FIX;-DELEV_FLOAT") + +add_subdirectory(r.watershed) diff --git a/raster/r.basins.fill/testsuite/testrbf.py b/raster/r.basins.fill/testsuite/testrbf.py index fdbcd4b548f..b9937b05689 100644 --- a/raster/r.basins.fill/testsuite/testrbf.py +++ b/raster/r.basins.fill/testsuite/testrbf.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + import unittest from grass.gunittest.case import TestCase diff --git a/raster/r.carve/main.c b/raster/r.carve/main.c index 37c237ba5cf..a242d3e6f16 100644 --- a/raster/r.carve/main.c +++ b/raster/r.carve/main.c @@ -204,7 +204,7 @@ static int init_projection(struct Cell_head *window, int *wrap_ncols) *wrap_ncols = (360.0 - (window->east - window->west)) / window->ew_res + 1.1; #else - G_fatal_error(_("Lat/Long location is not supported by %s. Please " + G_fatal_error(_("Lat/Long project is not supported by %s. Please " "reproject map first."), G_program_name()); #endif diff --git a/raster/r.colors.out/CMakeLists.txt b/raster/r.colors.out/CMakeLists.txt new file mode 100644 index 00000000000..0a9c64e8714 --- /dev/null +++ b/raster/r.colors.out/CMakeLists.txt @@ -0,0 +1,20 @@ +set(r_colors_out_SRCS raster_main.c) +set(r3_colors_out_SRCS raster3d_main.c) + +build_program( + NAME + r.colors.out + SOURCES + "${r_colors_out_SRCS}" + DEPENDS + grass_gis + grass_raster) + +build_program( + NAME + r3.colors.out + SOURCES + "${r3_colors_out_SRCS}" + DEPENDS + grass_gis + grass_raster3d) diff --git a/raster/r.colors/CMakeLists.txt b/raster/r.colors/CMakeLists.txt new file mode 100644 index 00000000000..084855195f4 --- /dev/null +++ b/raster/r.colors/CMakeLists.txt @@ -0,0 +1,20 @@ +set(r_colors_SRCS raster_main.c edit_colors.c rules.c stats.c) +set(r3_colors_SRCS raster3d_main.c edit_colors.c rules.c stats.c) + +build_program( + NAME + r.colors + SOURCES + "${r_colors_SRCS}" + DEPENDS + grass_gis + grass_raster3d) + +build_program( + NAME + r3.colors + SOURCES + "${r3_colors_SRCS}" + DEPENDS + grass_gis + grass_raster3d) diff --git a/raster/r.external/main.c b/raster/r.external/main.c index c3ee9b8daf2..baf5b7c8ea0 100644 --- a/raster/r.external/main.c +++ b/raster/r.external/main.c @@ -98,10 +98,9 @@ int main(int argc, char *argv[]) flag.o = G_define_flag(); flag.o->key = 'o'; - flag.o->label = - _("Override projection check (use current location's projection)"); - flag.o->description = _( - "Assume that the dataset has same projection as the current location"); + flag.o->label = _("Override projection check (use current project's CRS)"); + flag.o->description = _("Assume that the dataset has the same coordinate " + "reference system as the current project"); flag.j = G_define_flag(); flag.j->key = 'j'; diff --git a/raster/r.external/proj.c b/raster/r.external/proj.c index 0e38578fe06..7b9b8043133 100644 --- a/raster/r.external/proj.c +++ b/raster/r.external/proj.c @@ -130,15 +130,16 @@ void check_projection(struct Cell_head *cellhd, GDALDatasetH hDS, char *outloc, if (outloc != NULL) { /* do not create a xy location if an existing SRS was unreadable */ if (proj_trouble == 2) { - G_fatal_error(_("Unable to convert input map projection to GRASS " - "format; cannot create new location.")); + G_fatal_error( + _("Unable to convert input map coordinate reference " + "system to GRASS format; cannot create new project.")); } else { if (0 != G_make_location_crs(outloc, cellhd, proj_info, proj_units, srid, wkt)) { - G_fatal_error(_("Unable to create new location <%s>"), outloc); + G_fatal_error(_("Unable to create new project <%s>"), outloc); } - G_message(_("Location <%s> created"), outloc); + G_message(_("Project <%s> created"), outloc); G_unset_window(); /* new location, projection, and window */ G_get_window(cellhd); @@ -195,14 +196,15 @@ void check_projection(struct Cell_head *cellhd, GDALDatasetH hDS, char *outloc, proj_info, proj_units)) != 1) { int i_value; - strcpy(error_msg, _("Projection of dataset does not" - " appear to match current location.\n\n")); + strcpy(error_msg, + _("Coordinate reference system of dataset does not" + " appear to match current project.\n\n")); /* TODO: output this info sorted by key: */ if (loc_wind.proj != cellhd->proj || err != -2) { /* error in proj_info */ if (loc_proj_info != NULL) { - strcat(error_msg, _("Location PROJ_INFO is:\n")); + strcat(error_msg, _("Project PROJ_INFO is:\n")); for (i_value = 0; i_value < loc_proj_info->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", @@ -211,22 +213,22 @@ void check_projection(struct Cell_head *cellhd, GDALDatasetH hDS, char *outloc, strcat(error_msg, "\n"); } else { - strcat(error_msg, _("Location PROJ_INFO is:\n")); + strcat(error_msg, _("Project PROJ_INFO is:\n")); if (loc_wind.proj == PROJECTION_XY) sprintf(error_msg + strlen(error_msg), - "Location proj = %d (unreferenced/unknown)\n", + "Project proj = %d (unreferenced/unknown)\n", loc_wind.proj); else if (loc_wind.proj == PROJECTION_LL) sprintf(error_msg + strlen(error_msg), - "Location proj = %d (lat/long)\n", + "Project proj = %d (lat/long)\n", loc_wind.proj); else if (loc_wind.proj == PROJECTION_UTM) sprintf(error_msg + strlen(error_msg), - "Location proj = %d (UTM), zone = %d\n", + "Project proj = %d (UTM), zone = %d\n", loc_wind.proj, cellhd->zone); else sprintf(error_msg + strlen(error_msg), - "Location proj = %d (unknown), zone = %d\n", + "Project proj = %d (unknown), zone = %d\n", loc_wind.proj, cellhd->zone); } @@ -300,7 +302,7 @@ void check_projection(struct Cell_head *cellhd, GDALDatasetH hDS, char *outloc, else { /* error in proj_units */ if (loc_proj_units != NULL) { - strcat(error_msg, "Location PROJ_UNITS is:\n"); + strcat(error_msg, "Project PROJ_UNITS is:\n"); for (i_value = 0; i_value < loc_proj_units->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", @@ -318,13 +320,14 @@ void check_projection(struct Cell_head *cellhd, GDALDatasetH hDS, char *outloc, } } if (!check_only) { - strcat(error_msg, _("\nIn case of no significant differences " - "in the projection definitions," - " use the -o flag to ignore them and use" - " current location definition.\n")); - strcat(error_msg, _("Consider generating a new location from " + strcat(error_msg, + _("\nIn case of no significant differences " + "in the coordinate reference system definitions," + " use the -o flag to ignore them and use" + " current project definition.\n")); + strcat(error_msg, _("Consider generating a new project from " "the input dataset using " - "the 'location' parameter.\n")); + "the 'project' parameter.\n")); } if (check_only) @@ -342,8 +345,8 @@ void check_projection(struct Cell_head *cellhd, GDALDatasetH hDS, char *outloc, msg_fn = G_message; else msg_fn = G_verbose_message; - msg_fn(_("Projection of input dataset and current location " - "appear to match")); + msg_fn(_("Coordinate reference system of input dataset and current " + "project appear to match")); if (check_only) { GDALClose(hDS); exit(EXIT_SUCCESS); diff --git a/raster/r.external/testsuite/test_r_external.py b/raster/r.external/testsuite/test_r_external.py index 839a724a5b7..a22498eb773 100644 --- a/raster/r.external/testsuite/test_r_external.py +++ b/raster/r.external/testsuite/test_r_external.py @@ -2,6 +2,7 @@ @author Markus Neteler """ + from grass.gunittest.case import TestCase diff --git a/raster/r.external/window.c b/raster/r.external/window.c index d8adadfba44..7d627488d94 100644 --- a/raster/r.external/window.c +++ b/raster/r.external/window.c @@ -91,7 +91,7 @@ void update_default_window(struct Cell_head *cellhd) if (strcmp(G_mapset(), "PERMANENT") == 0) { G_put_element_window(&cur_wind, "", "DEFAULT_WIND"); - G_message(_("Default region for this location updated")); + G_message(_("Default region for this project updated")); } G_put_window(&cur_wind); G_message(_("Region for the current mapset updated")); diff --git a/raster/r.gwflow/main.c b/raster/r.gwflow/main.c index 3cf5131b4b7..a3106563606 100644 --- a/raster/r.gwflow/main.c +++ b/raster/r.gwflow/main.c @@ -233,7 +233,7 @@ int main(int argc, char *argv[]) /* Make sure that the current projection is not lat/long */ if ((G_projection() == PROJECTION_LL)) - G_fatal_error(_("Lat/Long location is not supported by %s. Please " + G_fatal_error(_("Lat/Long project is not supported by %s. Please " "reproject map first."), G_program_name()); diff --git a/raster/r.gwflow/testsuite/validation_7x7_grid.py b/raster/r.gwflow/testsuite/validation_7x7_grid.py index f4595eaf421..6d632092300 100644 --- a/raster/r.gwflow/testsuite/validation_7x7_grid.py +++ b/raster/r.gwflow/testsuite/validation_7x7_grid.py @@ -7,6 +7,7 @@ @author Soeren Gebbert """ + from grass.gunittest.case import TestCase diff --git a/raster/r.horizon/testsuite/test_r_horizon.py b/raster/r.horizon/testsuite/test_r_horizon.py index 4118c1cb203..846988401dc 100644 --- a/raster/r.horizon/testsuite/test_r_horizon.py +++ b/raster/r.horizon/testsuite/test_r_horizon.py @@ -11,6 +11,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + import json from grass.gunittest.case import TestCase diff --git a/raster/r.in.ascii/testsuite/test_r_in_ascii.py b/raster/r.in.ascii/testsuite/test_r_in_ascii.py index 151b6ff7978..20e0c2a8f9e 100644 --- a/raster/r.in.ascii/testsuite/test_r_in_ascii.py +++ b/raster/r.in.ascii/testsuite/test_r_in_ascii.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.script.core import read_command diff --git a/raster/r.in.gdal/testsuite/test_r_in_gdal.py b/raster/r.in.gdal/testsuite/test_r_in_gdal.py index 3e3f6bcd554..2b8bee0982a 100644 --- a/raster/r.in.gdal/testsuite/test_r_in_gdal.py +++ b/raster/r.in.gdal/testsuite/test_r_in_gdal.py @@ -2,6 +2,7 @@ @author Soeren Gebbert """ + from grass.gunittest.case import TestCase diff --git a/raster/r.in.lidar/main.c b/raster/r.in.lidar/main.c index 9c7d4cdad8f..68d3a0fcd1b 100644 --- a/raster/r.in.lidar/main.c +++ b/raster/r.in.lidar/main.c @@ -300,9 +300,10 @@ int main(int argc, char *argv[]) over_flag = G_define_flag(); over_flag->key = 'o'; over_flag->label = - _("Override projection check (use current location's projection)"); - over_flag->description = _( - "Assume that the dataset has same projection as the current location"); + _("Override projection check (use current project's CRS)"); + over_flag->description = + _("Assume that the dataset has the same coordinate reference system as " + "the current project"); scan_flag = G_define_flag(); scan_flag->key = 's'; diff --git a/raster/r.in.lidar/projection.c b/raster/r.in.lidar/projection.c index faf123db11b..4bb3799a764 100644 --- a/raster/r.in.lidar/projection.c +++ b/raster/r.in.lidar/projection.c @@ -29,13 +29,13 @@ void projection_mismatch_report(struct Cell_head cellhd, int i_value; char error_msg[8192]; - strcpy(error_msg, _("Projection of dataset does not" - " appear to match current location.\n\n")); + strcpy(error_msg, _("Coordinate reference system of dataset does not" + " appear to match current project.\n\n")); /* TODO: output this info sorted by key: */ if (loc_wind.proj != cellhd.proj || err != -2) { if (loc_proj_info != NULL) { - strcat(error_msg, _("GRASS LOCATION PROJ_INFO is:\n")); + strcat(error_msg, _("GRASS project PROJ_INFO is:\n")); for (i_value = 0; i_value < loc_proj_info->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", loc_proj_info->key[i_value], @@ -86,12 +86,12 @@ void projection_mismatch_report(struct Cell_head cellhd, } } sprintf(error_msg + strlen(error_msg), - _("\nIn case of no significant differences in the projection " - "definitions," + _("\nIn case of no significant differences" + " in the coordinate reference system definitions," " use the -o flag to ignore them and use" - " current location definition.\n")); + " current project definition.\n")); strcat(error_msg, - _("Consider generating a new location with 'location' parameter" + _("Consider generating a new project with 'project' parameter" " from input data set.\n")); G_fatal_error("%s", error_msg); } @@ -132,7 +132,8 @@ void projection_check_wkt(struct Cell_head cellhd, struct Cell_head loc_wind, loc_proj_units, proj_info, proj_units, err); } else if (verbose) { - G_message(_("Projection of input dataset and current location " - "appear to match")); + G_message(_( + "Coordinate reference system of input dataset and current project " + "appear to match")); } } diff --git a/raster/r.in.lidar/r.in.lidar.html b/raster/r.in.lidar/r.in.lidar.html index ff32c8291c2..6cff187c089 100644 --- a/raster/r.in.lidar/r.in.lidar.html +++ b/raster/r.in.lidar/r.in.lidar.html @@ -464,7 +464,7 @@

    Serpent Mound dataset

    # using v.in.lidar to create a new project # create project with CRS information of the LAS data -v.in.lidar -i input="Serpent Mound Model LAS Data.las" location=Serpent_Mound +v.in.lidar -i input="Serpent Mound Model LAS Data.las" project=Serpent_Mound # quit and restart GRASS in the newly created project "Serpent_Mound" diff --git a/raster/r.in.pdal/main.cpp b/raster/r.in.pdal/main.cpp index 63ab5c19f03..093b17258e1 100644 --- a/raster/r.in.pdal/main.cpp +++ b/raster/r.in.pdal/main.cpp @@ -248,10 +248,10 @@ int main(int argc, char *argv[]) reproject_flag->key = 'w'; reproject_flag->label = - _("Reproject to location's coordinate system if needed"); + _("Reproject to project's coordinate system if needed"); reproject_flag->description = _("Reprojects input dataset to the coordinate system of" - " the GRASS location (by default only datasets with the" + " the GRASS project (by default only datasets with" " matching coordinate system can be imported"); reproject_flag->guisection = _("Projection"); @@ -393,9 +393,10 @@ int main(int argc, char *argv[]) over_flag->key = 'o'; over_flag->label = - _("Override projection check (use current location's projection)"); - over_flag->description = _( - "Assume that the dataset has same projection as the current location"); + _("Override projection check (use current project's CRS)"); + over_flag->description = + _("Assume that the dataset has the same coordinate reference system as " + "the current project"); over_flag->guisection = _("Projection"); Flag *base_rast_res_flag = G_define_flag(); @@ -731,7 +732,7 @@ int main(int argc, char *argv[]) // we reproject when requested regardless of the input projection if (reproject_flag->answer) { - G_message(_("Reprojecting the input to the location projection")); + G_message(_("Reprojecting the input to the project's CRS")); char *proj_wkt = location_projection_as_wkt(false); pdal::Options o4; @@ -781,8 +782,8 @@ int main(int argc, char *argv[]) // getting projection is possible only after prepare if (over_flag->answer) { G_important_message(_("Overriding projection check and assuming" - " that the projection of input matches" - " the location projection")); + " that the CRS of input matches" + " the project's CRS")); } else if (!reproject_flag->answer) { pdal::SpatialReference spatial_reference = diff --git a/raster/r.in.pdal/projection.c b/raster/r.in.pdal/projection.c index 244ee323afb..206234d07a8 100644 --- a/raster/r.in.pdal/projection.c +++ b/raster/r.in.pdal/projection.c @@ -27,13 +27,13 @@ void projection_mismatch_report(struct Cell_head cellhd, int i_value; char error_msg[8192]; - strcpy(error_msg, _("Projection of dataset does not" - " appear to match current location.\n\n")); + strcpy(error_msg, _("Coordinate reference system of dataset does not" + " appear to match current project.\n\n")); /* TODO: output this info sorted by key: */ if (loc_wind.proj != cellhd.proj || err != -2) { if (loc_proj_info != NULL) { - strcat(error_msg, _("GRASS LOCATION PROJ_INFO is:\n")); + strcat(error_msg, _("GRASS project PROJ_INFO is:\n")); for (i_value = 0; i_value < loc_proj_info->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", loc_proj_info->key[i_value], @@ -68,7 +68,7 @@ void projection_mismatch_report(struct Cell_head cellhd, } else { if (loc_proj_units != NULL) { - strcat(error_msg, "GRASS LOCATION PROJ_UNITS is:\n"); + strcat(error_msg, "GRASS project PROJ_UNITS is:\n"); for (i_value = 0; i_value < loc_proj_units->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", loc_proj_units->key[i_value], @@ -84,12 +84,12 @@ void projection_mismatch_report(struct Cell_head cellhd, } } sprintf(error_msg + strlen(error_msg), - _("\nIn case of no significant differences in the projection " - "definitions," + _("\nIn case of no significant differences" + " in the coordinate reference system definitions," " use the -o flag to ignore them and use" - " current location definition.\n")); + " current project definition.\n")); strcat(error_msg, - _("Consider generating a new location with 'location' parameter" + _("Consider generating a new project with 'project' parameter" " from input data set.\n")); G_fatal_error("%s", error_msg); } @@ -131,8 +131,8 @@ void projection_check_wkt(struct Cell_head cellhd, struct Cell_head loc_wind, } else { if (verbose) { - G_message(_("Projection of input dataset and current location " - "appear to match")); + G_message(_("Coordinate reference system of input dataset and " + "current project appear to match")); } } } diff --git a/raster/r.in.pdal/r.in.pdal.html b/raster/r.in.pdal/r.in.pdal.html index 3dd9d068ac7..92cd25205e8 100644 --- a/raster/r.in.pdal/r.in.pdal.html +++ b/raster/r.in.pdal/r.in.pdal.html @@ -522,7 +522,7 @@

    Serpent Mound dataset

    # using v.in.lidar to create a new project # create a project with CRS information of the LAS data -v.in.lidar -i input="Serpent Mound Model LAS Data.las" location=Serpent_Mound +v.in.lidar -i input="Serpent Mound Model LAS Data.las" project=Serpent_Mound # quit and restart GRASS in the newly created project "Serpent_Mound" diff --git a/raster/r.info/testsuite/test_r_info.py b/raster/r.info/testsuite/test_r_info.py index 05953ae56b4..a4d554232dd 100644 --- a/raster/r.info/testsuite/test_r_info.py +++ b/raster/r.info/testsuite/test_r_info.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/raster/r.li/CMakeLists.txt b/raster/r.li/CMakeLists.txt new file mode 100644 index 00000000000..8444c2459ef --- /dev/null +++ b/raster/r.li/CMakeLists.txt @@ -0,0 +1,32 @@ +set(SUBDIRS1 + r.li.cwed + r.li.dominance + r.li.edgedensity + r.li.mpa + r.li.mps + r.li.padcv + r.li.padrange + r.li.padsd + r.li.patchdensity + r.li.patchnum + r.li.pielou + r.li.renyi + r.li.richness + r.li.shannon + r.li.shape + r.li.simpson) +# r.li.setup + +build_library_in_subdir( + r.li.daemon + NAME + grass_rli + DEPENDS + grass_gis + grass_raster + HTML_FILE_NAME + "r.li.daemon") + +foreach(SUBDIR ${SUBDIRS1}) + build_program_in_subdir(${SUBDIR} DEPENDS grass_rli) +endforeach() diff --git a/raster/r.li/r.li.daemon/daemon.c b/raster/r.li/r.li.daemon/daemon.c index 2ddee5a5c43..d1f31d9b8a5 100644 --- a/raster/r.li/r.li.daemon/daemon.c +++ b/raster/r.li/r.li.daemon/daemon.c @@ -23,7 +23,7 @@ #include #include -#ifdef __MINGW32__ +#ifdef _WIN32 #include #else #include diff --git a/raster/r.li/r.li.daemon/worker.c b/raster/r.li/r.li.daemon/worker.c index 83bfa62cc67..c272334595e 100644 --- a/raster/r.li/r.li.daemon/worker.c +++ b/raster/r.li/r.li.daemon/worker.c @@ -22,7 +22,7 @@ #include #include -#ifdef __MINGW32__ +#ifdef _WIN32 #include #else #include diff --git a/raster/r.mapcalc/CMakeLists.txt b/raster/r.mapcalc/CMakeLists.txt new file mode 100644 index 00000000000..7ac43843f80 --- /dev/null +++ b/raster/r.mapcalc/CMakeLists.txt @@ -0,0 +1,44 @@ +flex_target(mapcalc.yy.c mapcalc.l ${CMAKE_CURRENT_BINARY_DIR}/mapcalc.yy.c) +bison_target(mapcalc.tab.c mapcalc.y ${CMAKE_CURRENT_BINARY_DIR}/mapcalc.tab.c) +add_flex_bison_dependency(mapcalc.yy.c mapcalc.tab.c) +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/mapcalc.yy.c GENERATED) +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/mapcalc.tab.c GENERATED) + +set(r_mapcalc_common_SRCS + column_shift.c + evaluate.c + expression.c + function.c + main.c + xrowcol.c + ${CMAKE_CURRENT_BINARY_DIR}/mapcalc.tab.c + ${CMAKE_CURRENT_BINARY_DIR}/mapcalc.yy.c) + +set(r_mapcalc_SRCS ${r_mapcalc_common_SRCS} map.c xarea.c xcoor.c xres.c) +set(r3_mapcalc_SRCS ${r_mapcalc_common_SRCS} map3.c xarea.c xcoor3.c xres3.c) + +build_program( + NAME + r.mapcalc + SOURCES + "${r_mapcalc_SRCS}" + DEPENDS + grass_gis + grass_btree + grass_calc + grass_raster + OPTIONAL_DEPENDS + READLINE) + +build_program( + NAME + r3.mapcalc + SOURCES + "${r3_mapcalc_SRCS}" + DEPENDS + grass_gis + grass_btree + grass_calc + grass_raster3d + OPTIONAL_DEPENDS + READLINE) diff --git a/raster/r.param.scale/main.c b/raster/r.param.scale/main.c index 51fe02d8b05..095344ac999 100644 --- a/raster/r.param.scale/main.c +++ b/raster/r.param.scale/main.c @@ -36,7 +36,7 @@ int main(int argc, char **argv) /* Make sure that the current projection is not lat/long */ if ((G_projection() == PROJECTION_LL)) - G_fatal_error(_("Lat/Long locations are not supported by this module")); + G_fatal_error(_("Lat/Long projects are not supported by this module")); open_files(); diff --git a/raster/r.profile/main.c b/raster/r.profile/main.c index 6298ed7cc35..2a0701398e8 100644 --- a/raster/r.profile/main.c +++ b/raster/r.profile/main.c @@ -99,8 +99,8 @@ int main(int argc, char *argv[]) parm.units->options = "meters,kilometers,feet,miles"; parm.units->label = parm.units->description; parm.units->description = - _("If units are not specified, current location units are used. " - "Meters are used by default in geographic (latlon) locations."); + _("If units are not specified, current project units are used. " + "Meters are used by default in geographic (latlon) projects."); if (G_parser(argc, argv)) exit(EXIT_FAILURE); diff --git a/raster/r.random.cells/testsuite/test_random_cells.py b/raster/r.random.cells/testsuite/test_random_cells.py index 9faeb3b0135..0d4ca4379e5 100644 --- a/raster/r.random.cells/testsuite/test_random_cells.py +++ b/raster/r.random.cells/testsuite/test_random_cells.py @@ -12,7 +12,6 @@ for details. """ - from grass.gunittest.case import TestCase from grass.gunittest.main import test diff --git a/raster/r.random/testsuite/testrandom.py b/raster/r.random/testsuite/testrandom.py index 791aebfa669..e2bc2e413a3 100644 --- a/raster/r.random/testsuite/testrandom.py +++ b/raster/r.random/testsuite/testrandom.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule diff --git a/raster/r.reclass/testsuite/test_r_reclass.py b/raster/r.reclass/testsuite/test_r_reclass.py index 71d63d1c4bb..3f4ecfdf6a3 100644 --- a/raster/r.reclass/testsuite/test_r_reclass.py +++ b/raster/r.reclass/testsuite/test_r_reclass.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule diff --git a/raster/r.report/header.c b/raster/r.report/header.c index 5606ac1d6cf..1d0437c4c27 100644 --- a/raster/r.report/header.c +++ b/raster/r.report/header.c @@ -36,7 +36,7 @@ int header(int unit1, int unit2) if (page == 1 && with_headers) { lcr("", "RASTER MAP CATEGORY REPORT", "", buf, page_width - 2); pbuf(buf); - sprintf(tbuf1, "LOCATION: %s", G_location()); + sprintf(tbuf1, "PROJECT: %s", G_location()); if (with_headers && (page_length > 0)) sprintf(tbuf2, "Page %d", page); else diff --git a/raster/r.report/r.report.html b/raster/r.report/r.report.html index e2355899746..d4706471e3e 100644 --- a/raster/r.report/r.report.html +++ b/raster/r.report/r.report.html @@ -59,7 +59,7 @@

    EXAMPLE

     +-----------------------------------------------------------------------------+
     |                         RASTER MAP CATEGORY REPORT                          |
    -|LOCATION: nc_spm_08_grass7                           Fri Dec  6 17:00:21 2013|
    +|PROJECT: nc_spm_08_grass7                            Fri Dec  6 17:00:21 2013|
     |-----------------------------------------------------------------------------|
     |          north: 279073.97546639    east: 798143.31179672                    |
     |REGION    south: 113673.97546639    west: 595143.31179672                    |
    @@ -96,7 +96,7 @@ 

    EXAMPLE

     +-----------------------------------------------------------------------------+
     |                         RASTER MAP CATEGORY REPORT                          |
    -|LOCATION: nc_spm_08_latest                           Tue Feb 11 10:10:46 2014|
    +|PROJECT: nc_spm_08_latest                            Tue Feb 11 10:10:46 2014|
     |-----------------------------------------------------------------------------|
     |          north: 228527.25    east: 644971                                   |
     |REGION    south: 215018.25    west: 629980                                   |
    diff --git a/raster/r.series.interp/testsuite/interp_test.py b/raster/r.series.interp/testsuite/interp_test.py
    index 017912172be..e4cadd251cd 100644
    --- a/raster/r.series.interp/testsuite/interp_test.py
    +++ b/raster/r.series.interp/testsuite/interp_test.py
    @@ -1,6 +1,7 @@
     """Test of r.series.interp
     @author Soeren Gebbert
     """
    +
     from grass.gunittest.case import TestCase
     
     
    diff --git a/raster/r.sim/CMakeLists.txt b/raster/r.sim/CMakeLists.txt
    new file mode 100644
    index 00000000000..8e50cc05626
    --- /dev/null
    +++ b/raster/r.sim/CMakeLists.txt
    @@ -0,0 +1,35 @@
    +build_library_in_subdir(
    +  simlib
    +  NAME
    +  grass_sim
    +  DEPENDS
    +  grass_datetime
    +  grass_raster
    +  grass_vector
    +  OPTIONAL_DEPENDS
    +  OPENMP
    +  HEADERS
    +  "waterglobs.h"
    +  "simlib.h")
    +
    +build_program_in_subdir(
    +  r.sim.water
    +  DEPENDS
    +  grass_gis
    +  grass_gmath
    +  grass_sim
    +  OPTIONAL_DEPENDS
    +  OPENMP
    +  INCLUDES
    +  "../simlib")
    +
    +build_program_in_subdir(
    +  r.sim.sediment
    +  DEPENDS
    +  grass_gis
    +  grass_gmath
    +  grass_sim
    +  OPTIONAL_DEPENDS
    +  OPENMP
    +  INCLUDES
    +  "../simlib")
    diff --git a/raster/r.sim/simlib/waterglobs.h b/raster/r.sim/simlib/waterglobs.h
    index 7bf9fab74f2..30261ba3d42 100644
    --- a/raster/r.sim/simlib/waterglobs.h
    +++ b/raster/r.sim/simlib/waterglobs.h
    @@ -6,6 +6,10 @@
     #define UNDEF -9999
     
     #include 
    +#ifdef _MSC_VER
    +#undef min
    +#undef max
    +#endif
     
     extern char *elevin;
     extern char *dxin;
    diff --git a/raster/r.solute.transport/main.c b/raster/r.solute.transport/main.c
    index e699a19a93f..322b108910a 100644
    --- a/raster/r.solute.transport/main.c
    +++ b/raster/r.solute.transport/main.c
    @@ -240,7 +240,7 @@ int main(int argc, char *argv[])
     
         /* Make sure that the current projection is not lat/long */
         if ((G_projection() == PROJECTION_LL))
    -        G_fatal_error(_("Lat/Long location is not supported by %s. Please "
    +        G_fatal_error(_("Lat/Long project is not supported by %s. Please "
                             "reproject map first."),
                           G_program_name());
     
    diff --git a/raster/r.spread/CMakeLists.txt b/raster/r.spread/CMakeLists.txt
    new file mode 100644
    index 00000000000..46078279c58
    --- /dev/null
    +++ b/raster/r.spread/CMakeLists.txt
    @@ -0,0 +1,25 @@
    +set(r_spread_SRCS
    +    collect_ori.c
    +    deleteHa.c
    +    fixHa.c
    +    get_minHa.c
    +    insert2Ha.c
    +    insertHa.c
    +    main.c
    +    pick_dist.c
    +    pick_ignite.c
    +    ram2out.c
    +    replaceHa.c
    +    select_linksB.c
    +    spot.c
    +    spread.c)
    +
    +build_program(
    +  NAME
    +  r.spread
    +  SOURCES
    +  "${r_spread_SRCS}"
    +  DEPENDS
    +  grass_gis
    +  grass_raster
    +  grass_display)
    diff --git a/raster/r.sun/main.c b/raster/r.sun/main.c
    index 30cd8af9b10..2b8babfe348 100644
    --- a/raster/r.sun/main.c
    +++ b/raster/r.sun/main.c
    @@ -801,14 +801,14 @@ int main(int argc, char *argv[])
             struct Key_Value *in_proj_info, *in_unit_info;
     
             if ((in_proj_info = G_get_projinfo()) == NULL)
    -            G_fatal_error(_("Can't get projection info of current location"));
    +            G_fatal_error(_("Can't get projection info of current project"));
     
             if ((in_unit_info = G_get_projunits()) == NULL)
    -            G_fatal_error(_("Can't get projection units of current location"));
    +            G_fatal_error(_("Can't get projection units of current project"));
     
             if (pj_get_kv(&iproj, in_proj_info, in_unit_info) < 0)
                 G_fatal_error(
    -                _("Can't get projection key values of current location"));
    +                _("Can't get projection key values of current project"));
     
             G_free_key_value(in_proj_info);
             G_free_key_value(in_unit_info);
    @@ -822,7 +822,7 @@ int main(int argc, char *argv[])
     
         if ((latin != NULL || longin != NULL) && (G_projection() == PROJECTION_LL))
             G_warning(_("latin and longin raster maps have no effect when in a "
    -                    "Lat/Lon location"));
    +                    "Lat/Lon project"));
         /* true about longin= when civiltime is used? */
         /* civiltime needs longin= but not latin= for non-LL projections -
            better would be it just use pj_proj() if it needs those?? */
    diff --git a/raster/r.sunhours/main.c b/raster/r.sunhours/main.c
    index fbf0bd6393f..b866a365b2f 100644
    --- a/raster/r.sunhours/main.c
    +++ b/raster/r.sunhours/main.c
    @@ -218,14 +218,14 @@ int main(int argc, char *argv[])
     
             /* read current projection info */
             if ((in_proj_info = G_get_projinfo()) == NULL)
    -            G_fatal_error(_("Cannot get projection info of current location"));
    +            G_fatal_error(_("Cannot get projection info of current project"));
     
             if ((in_unit_info = G_get_projunits()) == NULL)
    -            G_fatal_error(_("Cannot get projection units of current location"));
    +            G_fatal_error(_("Cannot get projection units of current project"));
     
             if (pj_get_kv(&iproj, in_proj_info, in_unit_info) < 0)
                 G_fatal_error(
    -                _("Cannot get projection key values of current location"));
    +                _("Cannot get projection key values of current project"));
     
             G_free_key_value(in_proj_info);
             G_free_key_value(in_unit_info);
    diff --git a/raster/r.sunmask/g_solposition.c b/raster/r.sunmask/g_solposition.c
    index 8c79ad0dc5d..46033adc68a 100644
    --- a/raster/r.sunmask/g_solposition.c
    +++ b/raster/r.sunmask/g_solposition.c
    @@ -64,7 +64,7 @@ long calc_solar_position(double longitude, double latitude, double timezone,
         /* we don't like to run G_calc_solar_position in xy locations */
         if (window.proj == 0)
             G_fatal_error(
    -            _("Unable to calculate sun position in un-projected locations. "
    +            _("Unable to calculate sun position in projects without CRS. "
                   "Specify sunposition directly."));
     
         pdat = &pd; /* point to the structure for convenience */
    @@ -98,21 +98,21 @@ long calc_solar_position(double longitude, double latitude, double timezone,
             /* read current projection info */
             if ((in_proj_info = G_get_projinfo()) == NULL)
                 G_fatal_error(
    -                _("Unable to get projection info of current location"));
    +                _("Unable to get projection info of current project"));
     
             if ((in_unit_info = G_get_projunits()) == NULL)
                 G_fatal_error(
    -                _("Unable to get projection units of current location"));
    +                _("Unable to get projection units of current project"));
     
             if (pj_get_kv(&iproj, in_proj_info, in_unit_info) < 0)
                 G_fatal_error(
    -                _("Unable to get projection key values of current location"));
    +                _("Unable to get projection key values of current project"));
     
             G_free_key_value(in_proj_info);
             G_free_key_value(in_unit_info);
     
             /* Try using pj_print_proj_params() instead of all this */
    -        G_debug(1, "Projection found in location:");
    +        G_debug(1, "Projection found in project:");
             G_debug(1, "IN: meter: %f zone: %i proj: %s (iproj struct)",
                     iproj.meters, iproj.zone, iproj.proj);
             G_debug(1, "IN coord: longitude: %f, latitude: %f", longitude,
    diff --git a/raster/r.support/testsuite/test_r_support.py b/raster/r.support/testsuite/test_r_support.py
    index f7b7dd9e917..9a024c4a723 100644
    --- a/raster/r.support/testsuite/test_r_support.py
    +++ b/raster/r.support/testsuite/test_r_support.py
    @@ -8,6 +8,7 @@
     Read the file COPYING that comes with GRASS
     for details
     """
    +
     import random
     import string
     
    diff --git a/raster/r.terraflow/common.cpp b/raster/r.terraflow/common.cpp
    index 854193476e0..964d6760585 100644
    --- a/raster/r.terraflow/common.cpp
    +++ b/raster/r.terraflow/common.cpp
    @@ -22,7 +22,7 @@
     #endif
     #include 
     
    -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
    +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) || defined(_MSC_VER)
     #include 
     #else
     #include 
    diff --git a/raster/r.terraflow/direction.h b/raster/r.terraflow/direction.h
    index d98d463f7af..609b8d5c734 100644
    --- a/raster/r.terraflow/direction.h
    +++ b/raster/r.terraflow/direction.h
    @@ -21,7 +21,7 @@
     
     #include 
     
    -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
    +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) || defined(_MSC_VER)
     #include 
     #else
     #include 
    diff --git a/raster/r.terraflow/filldepr.cpp b/raster/r.terraflow/filldepr.cpp
    index 82390d374b4..600cf9005b4 100644
    --- a/raster/r.terraflow/filldepr.cpp
    +++ b/raster/r.terraflow/filldepr.cpp
    @@ -22,6 +22,9 @@
     #include "unionFind.h"
     #include "common.h"
     
    +#ifdef _MSC_VER
    +#pragma warning(default : 4716)
    +#endif
     #define FLOOD_DEBUG if (0)
     
     /************************************************************/
    diff --git a/raster/r.terraflow/main.cpp b/raster/r.terraflow/main.cpp
    index a831de23f6b..4aa1475190d 100644
    --- a/raster/r.terraflow/main.cpp
    +++ b/raster/r.terraflow/main.cpp
    @@ -297,7 +297,7 @@ void record_args(int argc, char **argv)
             exit(1);
         }
     
    -#ifdef __MINGW32__
    +#ifdef _WIN32
         strcpy(buf, ctime(&t));
     #else
         ctime_r(&t, buf);
    diff --git a/raster/r.terraflow/stats.cpp b/raster/r.terraflow/stats.cpp
    index 5325d72e466..ba804679bba 100644
    --- a/raster/r.terraflow/stats.cpp
    +++ b/raster/r.terraflow/stats.cpp
    @@ -20,8 +20,10 @@
     #include 
     #include 
     #include 
    +#ifndef _MSC_VER
     #include 
    -#ifndef __MINGW32__
    +#endif
    +#ifndef _WIN32
     #include 
     #endif
     #include 
    diff --git a/raster/r.texture/testsuite/test_texture.py b/raster/r.texture/testsuite/test_texture.py
    index af24229e9ba..378eaaeabb5 100644
    --- a/raster/r.texture/testsuite/test_texture.py
    +++ b/raster/r.texture/testsuite/test_texture.py
    @@ -8,6 +8,7 @@
     	            License (>=v2). Read the file COPYING that comes with GRASS
     	            for details.
     """
    +
     from grass.gunittest.case import TestCase
     
     
    diff --git a/raster/r.tile/testsuite/testrt.py b/raster/r.tile/testsuite/testrt.py
    index c1da1d10cdf..6cb5a91c296 100644
    --- a/raster/r.tile/testsuite/testrt.py
    +++ b/raster/r.tile/testsuite/testrt.py
    @@ -8,6 +8,7 @@
     	            License (>=v2). Read the file COPYING that comes with GRASS
     	            for details.
     """
    +
     from grass.gunittest.case import TestCase
     from grass.gunittest.main import test
     
    diff --git a/raster/r.to.vect/lines_io.c b/raster/r.to.vect/lines_io.c
    index 31dad0b903d..a8120da67b5 100644
    --- a/raster/r.to.vect/lines_io.c
    +++ b/raster/r.to.vect/lines_io.c
    @@ -26,7 +26,7 @@
     #include 
     #include 
     
    -#ifdef __MINGW32__
    +#ifdef _WIN32
     #include 
     #else
     #include 
    diff --git a/raster/r.to.vect/testsuite/test_r_to_vect.py b/raster/r.to.vect/testsuite/test_r_to_vect.py
    index 57de45e4b77..7ba284d0261 100644
    --- a/raster/r.to.vect/testsuite/test_r_to_vect.py
    +++ b/raster/r.to.vect/testsuite/test_r_to_vect.py
    @@ -8,6 +8,7 @@
                 License (>=v2). Read the file COPYING that comes with GRASS
                 for details.
     """
    +
     from grass.gunittest.case import TestCase
     from grass.gunittest.main import test
     
    diff --git a/raster/r.to.vect/util.c b/raster/r.to.vect/util.c
    index 2a1498d88ec..93b629853b5 100644
    --- a/raster/r.to.vect/util.c
    +++ b/raster/r.to.vect/util.c
    @@ -1,7 +1,7 @@
     #include 
     #include 
     
    -#ifdef __MINGW32__
    +#ifdef _WIN32
     #include 
     #else
     #include 
    diff --git a/raster/r.topidx/main.c b/raster/r.topidx/main.c
    index fb6ccada890..e3a6b6ab75e 100644
    --- a/raster/r.topidx/main.c
    +++ b/raster/r.topidx/main.c
    @@ -53,7 +53,7 @@ int main(int argc, char **argv)
     
         /* Make sure that the current projection is not lat/long */
         if (G_projection() == PROJECTION_LL)
    -        G_fatal_error(_("Lat/Long location is not supported by %s. Please "
    +        G_fatal_error(_("Lat/Long project is not supported by %s. Please "
                             "reproject map first."),
                           G_program_name());
     
    diff --git a/raster/r.univar/CMakeLists.txt b/raster/r.univar/CMakeLists.txt
    new file mode 100644
    index 00000000000..d6c4a30b165
    --- /dev/null
    +++ b/raster/r.univar/CMakeLists.txt
    @@ -0,0 +1,24 @@
    +set(r_univar_SRCS r.univar_main.c sort.c stats.c)
    +set(r3_univar_SRCS r3.univar_main.c sort.c stats.c)
    +
    +build_program(
    +  NAME
    +  r.univar
    +  SOURCES
    +  "${r_univar_SRCS}"
    +  DEPENDS
    +  grass_gis
    +  grass_raster
    +  OPTIONAL_DEPENDS
    +  OPENMP)
    +
    +build_program(
    +  NAME
    +  r3.univar
    +  SOURCES
    +  "${r3_univar_SRCS}"
    +  DEPENDS
    +  grass_gis
    +  grass_raster3d
    +  OPTIONAL_DEPENDS
    +  OPENMP)
    diff --git a/raster/r.univar/testsuite/test_r_univar.py b/raster/r.univar/testsuite/test_r_univar.py
    index 368ff3faae0..c03aea5dcfa 100644
    --- a/raster/r.univar/testsuite/test_r_univar.py
    +++ b/raster/r.univar/testsuite/test_r_univar.py
    @@ -2,6 +2,7 @@
     
     @author Soeren Gebbert
     """
    +
     from grass.gunittest.case import TestCase
     
     
    diff --git a/raster/r.watershed/CMakeLists.txt b/raster/r.watershed/CMakeLists.txt
    new file mode 100644
    index 00000000000..3a5a883d2d7
    --- /dev/null
    +++ b/raster/r.watershed/CMakeLists.txt
    @@ -0,0 +1,21 @@
    +build_program_in_subdir(
    +  ram
    +  DEPENDS
    +  grass_gis
    +  grass_raster
    +  grass_btree2
    +  grass_gmath
    +  RUNTIME_OUTPUT_DIR
    +  etc/r.watershed)
    +
    +build_program_in_subdir(
    +  seg
    +  DEPENDS
    +  grass_gis
    +  grass_raster
    +  grass_gmath
    +  grass_segment
    +  RUNTIME_OUTPUT_DIR
    +  etc/r.watershed)
    +
    +build_program_in_subdir(front NAME r.watershed DEPENDS grass_gis grass_raster)
    diff --git a/raster/r.what/testsuite/testrw.py b/raster/r.what/testsuite/testrw.py
    index f63ae5dfe30..8184f534720 100644
    --- a/raster/r.what/testsuite/testrw.py
    +++ b/raster/r.what/testsuite/testrw.py
    @@ -8,6 +8,7 @@
     	            License (>=v2). Read the file COPYING that comes with GRASS
     	            for details.
     """
    +
     from grass.gunittest.case import TestCase
     from grass.gunittest.main import test
     from grass.gunittest.gmodules import SimpleModule
    diff --git a/raster3d/CMakeLists.txt b/raster3d/CMakeLists.txt
    new file mode 100644
    index 00000000000..f751522d910
    --- /dev/null
    +++ b/raster3d/CMakeLists.txt
    @@ -0,0 +1,60 @@
    +build_program_in_subdir(r3.cross.rast DEPENDS grass_gis grass_raster3d)
    +
    +add_subdirectory(r3.flow)
    +
    +build_program_in_subdir(r3.gradient DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.gwflow DEPENDS grass_gis grass_raster3d grass_gpde)
    +
    +build_program_in_subdir(r3.in.ascii DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.in.bin DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.info DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.mask DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.null DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.neighbors DEPENDS grass_gis grass_raster3d
    +                        grass_stats)
    +
    +build_program_in_subdir(r3.out.ascii DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.out.bin DEPENDS grass_gis grass_raster3d)
    +
    +if(NOT MSVC)
    +  build_program_in_subdir(r3.out.v5d DEPENDS grass_gis grass_raster3d)
    +endif()
    +
    +build_program_in_subdir(r3.retile DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.stats DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.support DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.timestamp DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.to.rast DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.out.vtk DEPENDS grass_gis grass_raster3d)
    +
    +build_program_in_subdir(r3.mkdspf DEPENDS grass_gis grass_raster3d grass_gpde
    +                        grass_dspf)
    +
    +build_program_in_subdir(
    +  r3.in.lidar
    +  DEPENDS
    +  grass_gis
    +  grass_raster3d
    +  grass_segment
    +  PRIMARY_DEPENDS
    +  LIBLAS)
    +
    +build_program_in_subdir(r3.out.netcdf DEPENDS grass_gis grass_raster3d
    +                        PRIMARY_DEPENDS NETCDF)
    +
    +# mode_t is not available on msvc. Discuss
    +if(NOT MSVC)
    +  build_program_in_subdir(r3.in.v5d DEPENDS grass_gis grass_raster3d)
    +endif()
    diff --git a/raster3d/r3.flow/CMakeLists.txt b/raster3d/r3.flow/CMakeLists.txt
    new file mode 100644
    index 00000000000..6fc652e2ec5
    --- /dev/null
    +++ b/raster3d/r3.flow/CMakeLists.txt
    @@ -0,0 +1,24 @@
    +set(r3_flow_SRCS main.c flowline.c integrate.c interpolate.c voxel_traversal.c)
    +
    +build_program(
    +  NAME
    +  r3.flow
    +  SOURCES
    +  "${r3_flow_SRCS}"
    +  DEPENDS
    +  grass_gis
    +  grass_raster3d
    +  grass_vector)
    +
    +set(test_r3flow_SRCS test_main.c flowline.c integrate.c interpolate.c
    +                     voxel_traversal.c)
    +
    +build_program(
    +  NAME
    +  test.r3flow
    +  SOURCES
    +  "${test_r3flow_SRCS}"
    +  DEPENDS
    +  grass_gis
    +  grass_raster3d
    +  grass_vector)
    diff --git a/raster3d/r3.flow/testsuite/r3flow_test.py b/raster3d/r3.flow/testsuite/r3flow_test.py
    index 8385f10559e..f7d013f38bd 100644
    --- a/raster3d/r3.flow/testsuite/r3flow_test.py
    +++ b/raster3d/r3.flow/testsuite/r3flow_test.py
    @@ -3,6 +3,7 @@
     
     @author Anna Petrasova
     """
    +
     import os
     from grass.gunittest.case import TestCase
     from grass.gunittest.main import test
    diff --git a/raster3d/r3.gradient/testsuite/r3gradient_test.py b/raster3d/r3.gradient/testsuite/r3gradient_test.py
    index 9d0814dac78..d41e0a74baa 100644
    --- a/raster3d/r3.gradient/testsuite/r3gradient_test.py
    +++ b/raster3d/r3.gradient/testsuite/r3gradient_test.py
    @@ -3,6 +3,7 @@
     
     @author Anna Petrasova
     """
    +
     from grass.gunittest.case import TestCase
     from grass.gunittest.main import test
     
    diff --git a/raster3d/r3.in.lidar/main.c b/raster3d/r3.in.lidar/main.c
    index cd622a6098f..6170a3f50ba 100644
    --- a/raster3d/r3.in.lidar/main.c
    +++ b/raster3d/r3.in.lidar/main.c
    @@ -287,9 +287,10 @@ int main(int argc, char *argv[])
         over_flag = G_define_flag();
         over_flag->key = 'o';
         over_flag->label =
    -        _("Override projection check (use current location's projection)");
    -    over_flag->description = _(
    -        "Assume that the dataset has same projection as the current location");
    +        _("Override projection check (use current projects's CRS)");
    +    over_flag->description =
    +        _("Assume that the dataset has the same coordinate "
    +          "reference system as the current project");
     
         print_flag = G_define_flag();
         print_flag->key = 'p';
    diff --git a/raster3d/r3.in.lidar/projection.c b/raster3d/r3.in.lidar/projection.c
    index 40eb4b6e289..a3ebea5d7f4 100644
    --- a/raster3d/r3.in.lidar/projection.c
    +++ b/raster3d/r3.in.lidar/projection.c
    @@ -30,8 +30,8 @@ void projection_mismatch_report(struct Cell_head cellhd,
         int i_value;
         char error_msg[8192];
     
    -    strcpy(error_msg, _("Projection of dataset does not"
    -                        " appear to match current location.\n\n"));
    +    strcpy(error_msg, _("Coordinate reference system of dataset does not"
    +                        " appear to match current project.\n\n"));
     
         /* TODO: output this info sorted by key: */
         if (loc_wind.proj != cellhd.proj || err != -2) {
    @@ -87,12 +87,12 @@ void projection_mismatch_report(struct Cell_head cellhd,
             }
         }
         sprintf(error_msg + strlen(error_msg),
    -            _("\nIn case of no significant differences in the projection "
    -              "definitions,"
    +            _("\nIn case of no significant differences in the"
    +              " coordinate reference system definitions,"
                   " use the -o flag to ignore them and use"
    -              " current location definition.\n"));
    +              " current project definition.\n"));
         strcat(error_msg,
    -           _("Consider generating a new location with 'location' parameter"
    +           _("Consider generating a new project with 'project' parameter"
                  " from input data set.\n"));
         G_fatal_error("%s", error_msg);
     }
    @@ -133,7 +133,8 @@ void projection_check_wkt(struct Cell_head cellhd, struct Cell_head loc_wind,
                                        loc_proj_units, proj_info, proj_units, err);
         }
         else if (verbose) {
    -        G_message(_("Projection of input dataset and current location "
    -                    "appear to match"));
    +        G_message(_(
    +            "Coordinate reference system of input dataset and current project "
    +            "appear to match"));
         }
     }
    diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
    new file mode 100644
    index 00000000000..e08cb05d61c
    --- /dev/null
    +++ b/scripts/CMakeLists.txt
    @@ -0,0 +1,116 @@
    +set(script_DIRS
    +    r.shade
    +    d.background
    +    d.correlate
    +    d.frame
    +    d.out.file
    +    d.to.rast
    +    d.polar
    +    d.rast.edit
    +    d.rast.leg
    +    d.redraw
    +    d.shade
    +    d.what.rast
    +    d.what.vect
    +    db.dropcolumn
    +    db.droptable
    +    db.in.ogr
    +    db.out.ogr
    +    db.test
    +    db.univar
    +    g.download.location
    +    g.extension
    +    g.extension.all
    +    g.manual
    +    g.search.modules
    +    i.band.library
    +    i.colors.enhance
    +    i.image.mosaic
    +    i.in.spotvgt
    +    i.oif
    +    i.pansharpen
    +    i.spectral
    +    i.tasscap
    +    m.proj
    +    r.blend
    +    r.buffer.lowmem
    +    r.colors.stddev
    +    r.fillnulls
    +    r.grow
    +    r.import
    +    r.in.aster
    +    r.in.srtm
    +    r.mask
    +    r.out.xyz
    +    r.pack
    +    r.plane
    +    r.reclass.area
    +    r.rgb
    +    r.semantic.label
    +    r.tileset
    +    r.unpack
    +    r3.in.xyz
    +    v.build.all
    +    v.centroids
    +    v.clip
    +    v.db.addcolumn
    +    v.db.addtable
    +    v.db.join
    +    v.db.dropcolumn
    +    v.db.droprow
    +    v.db.droptable
    +    v.db.renamecolumn
    +    v.db.reconnect.all
    +    v.db.univar
    +    v.db.update
    +    v.dissolve
    +    v.import
    +    v.in.e00
    +    v.in.geonames
    +    v.in.lines
    +    v.in.mapgen
    +    v.in.wfs
    +    v.rast.stats
    +    v.report
    +    v.pack
    +    v.to.lines
    +    v.unpack
    +    v.what.strds
    +    v.what.vect
    +    wxpyimgview
    +    r.mapcalc.simple
    +    r.in.wms)
    +
    +foreach(script_DIR ${script_DIRS})
    +  build_script_in_subdir(${script_DIR})
    +endforeach()
    +
    +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/r.in.wms
    +     DESTINATION ${CMAKE_BINARY_DIR}/etc/)
    +
    +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/wxpyimgview/wxpyimgview_gui.py
    +     DESTINATION ${CMAKE_BINARY_DIR}/etc/)
    +
    +add_custom_target(
    +  r.in.wms_files
    +  COMMAND ${CMAKE_COMMAND} -E make_directory ${GISBASE}/etc/r.in.wms/
    +  COMMAND
    +    ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/r.in.wms/wms_base.py
    +    ${GISBASE}/etc/r.in.wms/
    +  COMMAND
    +    ${CMAKE_COMMAND} -E copy
    +    ${CMAKE_CURRENT_SOURCE_DIR}/r.in.wms/wms_cap_parsers.py
    +    ${GISBASE}/etc/r.in.wms/
    +  COMMAND
    +    ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/r.in.wms/wms_drv.py
    +    ${GISBASE}/etc/r.in.wms/
    +  COMMAND
    +    ${CMAKE_COMMAND} -E copy
    +    ${CMAKE_CURRENT_SOURCE_DIR}/r.in.wms/wms_gdal_drv.py
    +    ${GISBASE}/etc/r.in.wms/
    +  COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/r.in.wms/srs.py
    +          ${GISBASE}/etc/r.in.wms/
    +  DEPENDS v.to.lines)
    +add_dependencies(r.in.wms r.in.wms_files)
    +
    +set_target_properties(r.in.wms_files PROPERTIES FOLDER scripts)
    diff --git a/scripts/d.frame/d.frame.py b/scripts/d.frame/d.frame.py
    index 9459dfdbbaa..2d75457bee0 100755
    --- a/scripts/d.frame/d.frame.py
    +++ b/scripts/d.frame/d.frame.py
    @@ -188,11 +188,11 @@ def calculate_frame(frame, at, width, height):
     
         This function does also the necessary formatting.
     
    -    >>> calculate_frame('apple', "0,49.8,0,50.2", 500, 500)
    +    >>> calculate_frame("apple", "0,49.8,0,50.2", 500, 500)
         'GRASS_RENDER_FRAME=251,500,0,251 # apple\\n'
    -    >>> calculate_frame('orange', "50.2,0,49.8,100", 500, 500)
    +    >>> calculate_frame("orange", "50.2,0,49.8,100", 500, 500)
         'GRASS_RENDER_FRAME=500,249,249,500 # orange\\n'
    -    >>> calculate_frame('odd_number', "0,49.8,0,50.2", 367, 367)
    +    >>> calculate_frame("odd_number", "0,49.8,0,50.2", 367, 367)
         'GRASS_RENDER_FRAME=184,367,0,184 # odd_number\\n'
     
         The following would give 182,367,0,184 if we would be truncating
    @@ -201,7 +201,7 @@ def calculate_frame(frame, at, width, height):
         0.502 times 367 is 184.234 which fits with the (correct) width of
         the frame which is 184.
     
    -    >>> calculate_frame('test_truncating_bug', "0,50.2,0,50.2", 367, 367)
    +    >>> calculate_frame("test_truncating_bug", "0,50.2,0,50.2", 367, 367)
         'GRASS_RENDER_FRAME=183,367,0,184 # test_truncating_bug\\n'
         """
         try:
    @@ -322,7 +322,8 @@ def main():
                 if options["at"]:
                     warning(
                         _(
    -                        "Frame <%s> already found. An existing frame can be overwritten by '%s' flag."
    +                        "Frame <%s> already found. An existing frame can be "
    +                        "overwritten by '%s' flag."
                         )
                         % (options["frame"], "--overwrite")
                     )
    diff --git a/scripts/d.polar/d.polar.py b/scripts/d.polar/d.polar.py
    index 051b958de1d..c1c35080cc8 100755
    --- a/scripts/d.polar/d.polar.py
    +++ b/scripts/d.polar/d.polar.py
    @@ -275,7 +275,7 @@ def plot_eps(psout):
     newpath
                                             %% coordinates of rescaled, translated outer circle follow
                                             %% first point moveto, then lineto
    -"""
    +"""  # noqa: E501
         )
         s = t.substitute(
             AXESLINEWIDTH=axeslinewidth,
    @@ -322,7 +322,7 @@ def plot_eps(psout):
     newpath
                                             %% coordinates of rescaled, translated diagram follow
                                             %% first point moveto, then lineto
    -"""
    +"""  # noqa: E501
         )
         s = t.substitute(
             AXESFONTSIZE=axesfontsize,
    @@ -364,7 +364,7 @@ def plot_eps(psout):
     newpath
                                             %% coordinates of rescaled, translated average direction follow
                                             %% first point moveto, second lineto
    -"""
    +"""  # noqa: E501
         )
         s = t.substitute(DIAGRAMLINEWIDTH=diagramlinewidth)
         outf.write(s)
    @@ -396,7 +396,7 @@ def plot_eps(psout):
     col1                                    %% colAVERAGE-DIRECTION-COLOR
     %% Line below: (AVERAGE-DIRECTION-STRING) LEGENDS-X AVERAGE-DIRECTION-LEGEND-Y 4 just-string
     ($AVERAGEDIRECTIONSTRING) $LEGENDSX $AVERAGEDIRECTIONLEGENDY 4 just-string
    -"""
    +"""  # noqa: E501
         )
         s = t.substitute(
             ALLDATALEGENDY=alldatalegendy,
    diff --git a/scripts/d.rast.edit/d.rast.edit.py b/scripts/d.rast.edit/d.rast.edit.py
    index a3e311079f6..4824a17a81c 100755
    --- a/scripts/d.rast.edit/d.rast.edit.py
    +++ b/scripts/d.rast.edit/d.rast.edit.py
    @@ -107,7 +107,10 @@
         "cols": ("cols", int),
     }
     
    -gray12_bits = b"\x00\x00\x22\x22\x00\x00\x88\x88\x00\x00\x22\x22\x00\x00\x88\x88\x00\x00\x22\x22\x00\x00\x88\x88\x00\x00\x22\x22\x00\x00\x88\x88"
    +gray12_bits = (
    +    b"\x00\x00\x22\x22\x00\x00\x88\x88\x00\x00\x22\x22\x00\x00\x88\x88\x00"
    +    b"\x00\x22\x22\x00\x00\x88\x88\x00\x00\x22\x22\x00\x00\x88\x88"
    +)
     
     
     def run(cmd, **kwargs):
    diff --git a/scripts/g.extension/g.extension.py b/scripts/g.extension/g.extension.py
    index 36362928c1d..3fd497d78cd 100644
    --- a/scripts/g.extension/g.extension.py
    +++ b/scripts/g.extension/g.extension.py
    @@ -16,8 +16,8 @@
     #
     # TODO:         - update temporary workaround of using grass7 subdir of addon-repo, see
     #                 https://github.com/OSGeo/grass-addons/issues/528
    -#               - add sudo support where needed (i.e. check first permission to write into
    -#                 $GISBASE directory)
    +#               - add sudo support where needed (i.e. check first permission to write
    +#                 into $GISBASE directory)
     #               - fix toolbox support in install_private_extension_xml()
     #############################################################################
     
    @@ -224,9 +224,11 @@ def __init__(
             #: Attribute containing the URL to the online repository
             self.url = url
             self.major_grass_version = major_grass_version
    -        #: Attribute flagging if the repository is structured like the official addons repository
    +        #: Attribute flagging if the repository is structured like the official addons
    +        # repository
             self.official_repository_structure = official_repository_structure
    -        #: Attribute containing the path to the working directory where the repo is cloned out to
    +        #: Attribute containing the path to the working directory where the repo is
    +        # cloned out to
             if working_directory:
                 self.working_directory = Path(working_directory).absolute()
             else:
    @@ -247,7 +249,8 @@ def __init__(
             self.default_branch = self._get_default_branch()
             #: Attribute containing the branch used for checkout
             self.branch = self._set_branch(branch)
    -        #: Attribute containing list of addons in the repository with path to directories
    +        #: Attribute containing list of addons in the repository with path to
    +        # directories
             self.addons = self._get_addons_list()
     
         def _get_version(self):
    @@ -350,7 +353,8 @@ def _get_version_branch(self):
         def _set_branch(self, branch_name):
             """Set the branch to check out to either:
             a) a user defined branch
    -        b) a version branch for repositories following the official addons repository structure
    +        b) a version branch for repositories following the official addons repository
    +           structure
             c) the default branch of the repository
             """
             checkout_branch = None
    @@ -547,12 +551,12 @@ def get_default_branch(full_url):
         # Construct API call and retrieve default branch
         api_calls = {
             "github.com": f"https://api.github.com/repos/{organization}/{repository}",
    -        "gitlab.com": f"https://gitlab.com/api/v4/projects/{organization}%2F{repository}",
    -        "bitbucket.org": f"https://api.bitbucket.org/2.0/repositories/{organization}/{repository}/branching-model?",
    +        "gitlab.com": f"https://gitlab.com/api/v4/projects/{organization}%2F{repository}",  # noqa: E501
    +        "bitbucket.org": f"https://api.bitbucket.org/2.0/repositories/{organization}/{repository}/branching-model?",  # noqa: E501
         }
    -    # Try to get default branch via API. The API call is known to fail a) if the full_url
    -    # does not belong to an implemented hosting service or b) if the rate limit of the
    -    # API is exceeded
    +    # Try to get default branch via API. The API call is known to fail a) if the
    +    # full_url does not belong to an implemented hosting service or b) if the rate
    +    # limit of the API is exceeded
         try:
             req = urlrequest.urlopen(api_calls.get(url_parts.netloc))
             content = json.loads(req.read())
    @@ -606,9 +610,9 @@ def expand_module_class_name(class_letters):
         The letter or letters are used in module names, e.g. r.slope.aspect.
         The names are used in directories in Addons but also in the source code.
     
    -    >>> expand_module_class_name('r')
    +    >>> expand_module_class_name("r")
         'raster'
    -    >>> expand_module_class_name('v')
    +    >>> expand_module_class_name("v")
         'vector'
         """
         name = {
    @@ -635,9 +639,9 @@ def get_module_class_name(module_name):
     
         The names are used in directories in Addons but also in the source code.
     
    -    >>> get_module_class_name('r.slope.aspect')
    +    >>> get_module_class_name("r.slope.aspect")
         'raster'
    -    >>> get_module_class_name('v.to.rast')
    +    >>> get_module_class_name("v.to.rast")
         'vector'
         """
         classchar = module_name.split(".", 1)[0]
    @@ -1590,7 +1594,8 @@ def install_module_xml(mlist):
                 tree.append(tnode)
             else:
                 gs.verbose(
    -                "Extension module already listed in metadata file; metadata not updated!"
    +                "Extension module already listed in metadata file; metadata not "
    +                "updated!"
                 )
         write_xml_modules(xml_file, tree)
     
    @@ -2503,9 +2508,9 @@ def resolve_xmlurl_prefix(url, source=None):
         It ensures that there is a single slash at the end of URL, so we can attach
          file name easily:
     
    -    >>> resolve_xmlurl_prefix('https://grass.osgeo.org/addons')
    +    >>> resolve_xmlurl_prefix("https://grass.osgeo.org/addons")
         'https://grass.osgeo.org/addons/'
    -    >>> resolve_xmlurl_prefix('https://grass.osgeo.org/addons/')
    +    >>> resolve_xmlurl_prefix("https://grass.osgeo.org/addons/")
         'https://grass.osgeo.org/addons/'
         """
         gs.debug("resolve_xmlurl_prefix(url={0}, source={1})".format(url, source))
    @@ -2655,58 +2660,62 @@ def resolve_source_code(url=None, name=None, branch=None, fork=False):
     
         Official repository:
     
    -    >>> resolve_source_code(name='g.example') # doctest: +SKIP
    +    >>> resolve_source_code(name="g.example")  # doctest: +SKIP
         ('official', 'https://trac.osgeo.org/.../general/g.example')
     
         Subversion:
     
    -    >>> resolve_source_code('https://svn.osgeo.org/grass/grass-addons/grass7')
    +    >>> resolve_source_code("https://svn.osgeo.org/grass/grass-addons/grass7")
         ('svn', 'https://svn.osgeo.org/grass/grass-addons/grass7')
     
         ZIP files online:
     
    -    >>> resolve_source_code('https://trac.osgeo.org/.../r.modis?format=zip') # doctest: +SKIP
    +    >>> resolve_source_code(
    +    ...     "https://trac.osgeo.org/.../r.modis?format=zip"
    +    ... )  # doctest: +SKIP
         ('remote_zip', 'https://trac.osgeo.org/.../r.modis?format=zip')
     
         Local directories and ZIP files:
     
    -    >>> resolve_source_code(os.path.expanduser("~")) # doctest: +ELLIPSIS
    +    >>> resolve_source_code(os.path.expanduser("~"))  # doctest: +ELLIPSIS
         ('dir', '...')
    -    >>> resolve_source_code('/local/directory/downloaded.zip') # doctest: +SKIP
    +    >>> resolve_source_code("/local/directory/downloaded.zip")  # doctest: +SKIP
         ('zip', '/local/directory/downloaded.zip')
     
         OSGeo Trac:
     
    -    >>> resolve_source_code('trac.osgeo.org/.../r.agent.aco') # doctest: +SKIP
    +    >>> resolve_source_code("trac.osgeo.org/.../r.agent.aco")  # doctest: +SKIP
         ('remote_zip', 'https://trac.osgeo.org/.../r.agent.aco?format=zip')
    -    >>> resolve_source_code('https://trac.osgeo.org/.../r.agent.aco') # doctest: +SKIP
    +    >>> resolve_source_code("https://trac.osgeo.org/.../r.agent.aco")  # doctest: +SKIP
         ('remote_zip', 'https://trac.osgeo.org/.../r.agent.aco?format=zip')
     
         GitHub:
     
    -    >>> resolve_source_code('github.com/user/g.example') # doctest: +SKIP
    +    >>> resolve_source_code("github.com/user/g.example")  # doctest: +SKIP
         ('remote_zip', 'https://github.com/user/g.example/archive/master.zip')
    -    >>> resolve_source_code('github.com/user/g.example/') # doctest: +SKIP
    +    >>> resolve_source_code("github.com/user/g.example/")  # doctest: +SKIP
         ('remote_zip', 'https://github.com/user/g.example/archive/master.zip')
    -    >>> resolve_source_code('https://github.com/user/g.example') # doctest: +SKIP
    +    >>> resolve_source_code("https://github.com/user/g.example")  # doctest: +SKIP
         ('remote_zip', 'https://github.com/user/g.example/archive/master.zip')
    -    >>> resolve_source_code('https://github.com/user/g.example/') # doctest: +SKIP
    +    >>> resolve_source_code("https://github.com/user/g.example/")  # doctest: +SKIP
         ('remote_zip', 'https://github.com/user/g.example/archive/master.zip')
     
         GitLab:
     
    -    >>> resolve_source_code('gitlab.com/JoeUser/GrassModule') # doctest: +SKIP
    +    >>> resolve_source_code("gitlab.com/JoeUser/GrassModule")  # doctest: +SKIP
         ('remote_zip', 'https://gitlab.com/JoeUser/GrassModule/-/archive/master/GrassModule-master.zip')
    -    >>> resolve_source_code('https://gitlab.com/JoeUser/GrassModule') # doctest: +SKIP
    +    >>> resolve_source_code("https://gitlab.com/JoeUser/GrassModule")  # doctest: +SKIP
         ('remote_zip', 'https://gitlab.com/JoeUser/GrassModule/-/archive/master/GrassModule-master.zip')
     
         Bitbucket:
     
    -    >>> resolve_source_code('bitbucket.org/joe-user/grass-module') # doctest: +SKIP
    +    >>> resolve_source_code("bitbucket.org/joe-user/grass-module")  # doctest: +SKIP
         ('remote_zip', 'https://bitbucket.org/joe-user/grass-module/get/default.zip')
    -    >>> resolve_source_code('https://bitbucket.org/joe-user/grass-module') # doctest: +SKIP
    +    >>> resolve_source_code(
    +    ...     "https://bitbucket.org/joe-user/grass-module"
    +    ... )  # doctest: +SKIP
         ('remote_zip', 'https://bitbucket.org/joe-user/grass-module/get/default.zip')
    -    """
    +    """  # noqa: E501
         # Handle URL for the official repo
         if not url or url == GIT_URL:
             return "official", GIT_URL
    diff --git a/scripts/i.image.mosaic/i.image.mosaic.py b/scripts/i.image.mosaic/i.image.mosaic.py
    index ddd89553b22..65ac5f2e38c 100755
    --- a/scripts/i.image.mosaic/i.image.mosaic.py
    +++ b/scripts/i.image.mosaic/i.image.mosaic.py
    @@ -12,8 +12,9 @@
     #               License (>=v2). Read the file COPYING that comes with GRASS
     #               for details.
     #
    -# TODO: - implement g.findfile for 3 and 4 maps (currently only current mapset supported)
    -#            [done for 2 maps]
    +# TODO: - implement g.findfile for 3 and 4 maps (currently only current mapset
    +#           supported)
    +#               [done for 2 maps]
     #       - fix isnull() in r.mapcalc for 3 and 4 maps composites
     #            [done for 2 maps]
     #       - fix color table length (currently only 256 cols supported, make
    diff --git a/scripts/i.in.spotvgt/i.in.spotvgt.py b/scripts/i.in.spotvgt/i.in.spotvgt.py
    index e0e0911c81a..1ee52d11c40 100755
    --- a/scripts/i.in.spotvgt/i.in.spotvgt.py
    +++ b/scripts/i.in.spotvgt/i.in.spotvgt.py
    @@ -67,7 +67,7 @@
           
         
      
    -"""
    +"""  # noqa: E501
     
     # a function for writing VRT files
     
    diff --git a/scripts/i.pansharpen/i.pansharpen.py b/scripts/i.pansharpen/i.pansharpen.py
    index dc6f15bcb5e..d0b06e53727 100755
    --- a/scripts/i.pansharpen/i.pansharpen.py
    +++ b/scripts/i.pansharpen/i.pansharpen.py
    @@ -426,7 +426,8 @@ def main():
             grass.message(_("Adjusting blue channel color table..."))
             blue_colors = ["0 0 0 0\n5% 0 0 0\n67% 255 255 255\n100% 255 255 255"]
             # these previous colors are way too blue for landsat
    -        # blue_colors = ['0 0 0 0\n10% 0 0 0\n20% 200 200 200\n40% 230 230 230\n67% 255 255 255\n100% 255 255 255']
    +        # blue_colors = ['0 0 0 0\n10% 0 0 0\n20% 200 200 200\n40% 230 230 230\n67%
    +        # 255 255 255\n100% 255 255 255']
             bc = grass.feed_command("r.colors", quiet=True, map="%s_blue" % out, rules="-")
             bc.stdin.write(grass.encode("\n".join(blue_colors)))
             bc.stdin.close()
    @@ -649,9 +650,9 @@ def pca(pan, ms1, ms2, ms3, out, pid, sproc):
             outg = "%s_green" % out
             outb = "%s_blue" % out
     
    -        cmd1 = "$outb = 1 * round(($panmatch1 * $b1evect1) + ($pca2 * $b1evect2) + ($pca3 * $b1evect3) + $b1mean)"
    -        cmd2 = "$outg = 1 * round(($panmatch2 * $b2evect1) + ($pca2 * $b2evect2) + ($pca3 * $b2evect3) + $b2mean)"
    -        cmd3 = "$outr = 1 * round(($panmatch3 * $b3evect1) + ($pca2 * $b3evect2) + ($pca3 * $b3evect3) + $b3mean)"
    +        cmd1 = "$outb = 1 * round(($panmatch1 * $b1evect1) + ($pca2 * $b1evect2) + ($pca3 * $b1evect3) + $b1mean)"  # noqa: E501
    +        cmd2 = "$outg = 1 * round(($panmatch2 * $b2evect1) + ($pca2 * $b2evect2) + ($pca3 * $b2evect3) + $b2mean)"  # noqa: E501
    +        cmd3 = "$outr = 1 * round(($panmatch3 * $b3evect1) + ($pca2 * $b3evect2) + ($pca3 * $b3evect3) + $b3mean)"  # noqa: E501
     
             cmd = "\n".join([cmd1, cmd2, cmd3])
     
    diff --git a/scripts/m.proj/m.proj.py b/scripts/m.proj/m.proj.py
    index 3aeafcc2cbf..6c5c2c0eed7 100755
    --- a/scripts/m.proj/m.proj.py
    +++ b/scripts/m.proj/m.proj.py
    @@ -163,7 +163,7 @@ def main():
         # set up projection params
         s = gcore.read_command("g.proj", flags="j")
         kv = parse_key_val(s)
    -    if "XY location" in kv["+proj"] and (ll_in or ll_out):
    +    if "XY location" in kv:
             gcore.fatal(_("Unable to project to or from a XY location"))
     
         in_proj = None
    diff --git a/scripts/r.colors.stddev/r.colors.stddev.py b/scripts/r.colors.stddev/r.colors.stddev.py
    index c7ff5a51770..e8d4321939f 100755
    --- a/scripts/r.colors.stddev/r.colors.stddev.py
    +++ b/scripts/r.colors.stddev/r.colors.stddev.py
    @@ -81,7 +81,8 @@ def main():
                 # r.reclass input="$GIS_OPT_MAP" output="${GIS_OPT_MAP}.stdevs" <<
                 # EOF
     
    -            # >3 S.D. outliers colored black so they show up in d.histogram w/ white background
    +            # >3 S.D. outliers colored black so they show up in d.histogram w/ white
    +            # background
                 rules = "\n".join(
                     [
                         "0% black",
    @@ -132,7 +133,8 @@ def main():
             else:
                 # zero centered banded  black/red/yellow/green/yellow/red/black
     
    -            # >3 S.D. outliers colored black so they show up in d.histogram w/ white background
    +            # >3 S.D. outliers colored black so they show up in d.histogram w/ white
    +            # background
                 rules = "\n".join(
                     [
                         "%f black" % -maxv,
    diff --git a/scripts/r.fillnulls/r.fillnulls.py b/scripts/r.fillnulls/r.fillnulls.py
    index 219f9dafa07..7744d01ca25 100755
    --- a/scripts/r.fillnulls/r.fillnulls.py
    +++ b/scripts/r.fillnulls/r.fillnulls.py
    @@ -188,7 +188,10 @@ def main():
             if usermask:
                 grass.message(_("Skipping masked raster parts"))
                 grass.mapcalc(
    -                '$tmp1 = if(isnull("$input") && !($mask == 0 || isnull($mask)),1,null())',
    +                (
    +                    '$tmp1 = if(isnull("$input") && !($mask == 0 || isnull($mask)),1,'
    +                    "null())"
    +                ),
                     tmp1=prefix + "nulls",
                     input=input,
                     mask=usermask,
    @@ -232,7 +235,8 @@ def main():
                     )
                 )
     
    -        # assign unique IDs to each hole or hole system (holes closer than edge distance)
    +        # assign unique IDs to each hole or hole system (holes closer than edge
    +        # distance)
             grass.message(_("Assigning IDs to NULL areas"))
             tmp_rmaps.append(prefix + "clumped")
             try:
    @@ -302,7 +306,8 @@ def main():
                 )
                 grass.warning(
                     _(
    -                    "Input map <%s> has no holes. Copying to output without modification."
    +                    "Input map <%s> has no holes. Copying to output without "
    +                    "modification."
                     )
                     % (input,)
                 )
    @@ -488,7 +493,8 @@ def main():
                     failed_list.append(holename)
                     continue
     
    -            # append hole result to interpolated version later used to patch into original DEM
    +            # append hole result to interpolated version later used to patch into
    +            # original DEM
                 if first:
                     tmp_rmaps.append(filling)
                     grass.run_command(
    @@ -572,7 +578,8 @@ def main():
                 except CalledModuleError:
                     grass.fatal(
                         _(
    -                        "abandoned. Removing temporary maps, restoring user mask if needed:"
    +                        "abandoned. Removing temporary maps, restoring user mask if "
    +                        "needed:"
                         )
                     )
     
    @@ -616,7 +623,8 @@ def main():
                         p.returncode = 0
                         grass.warning(
                             _(
    -                            "Input map <%s> has no holes. Copying to output without modification."
    +                            "Input map <%s> has no holes. Copying to output without "
    +                            "modification."
                             )
                             % (input,)
                         )
    @@ -648,7 +656,8 @@ def main():
                         p.returncode = 0
                         grass.warning(
                             _(
    -                            "Input map <%s> has no holes. Copying to output without modification."
    +                            "Input map <%s> has no holes. Copying to output without "
    +                            "modification."
                             )
                             % (input,)
                         )
    diff --git a/scripts/r.fillnulls/testsuite/test_r_fillnulls.py b/scripts/r.fillnulls/testsuite/test_r_fillnulls.py
    index 8cfed138f4e..975fd5330f2 100644
    --- a/scripts/r.fillnulls/testsuite/test_r_fillnulls.py
    +++ b/scripts/r.fillnulls/testsuite/test_r_fillnulls.py
    @@ -3,6 +3,7 @@
     
     @author: Sanjeet Bhatti
     """
    +
     import os
     
     from grass.gunittest.case import TestCase
    diff --git a/scripts/r.import/r.import.py b/scripts/r.import/r.import.py
    index b49fdb2439a..f9f2db56b75 100644
    --- a/scripts/r.import/r.import.py
    +++ b/scripts/r.import/r.import.py
    @@ -179,7 +179,8 @@ def main():
         elif tgtres == "value":
             grass.fatal(
                 _(
    -                "Please provide the resolution for the imported dataset or change to 'estimated' resolution"
    +                "Please provide the resolution for the imported dataset or change to "
    +                "'estimated' resolution"
                 )
             )
     
    diff --git a/scripts/r.in.srtm/r.in.srtm.py b/scripts/r.in.srtm/r.in.srtm.py
    index d88a560d49c..3aa4db4f6be 100755
    --- a/scripts/r.in.srtm/r.in.srtm.py
    +++ b/scripts/r.in.srtm/r.in.srtm.py
    @@ -133,7 +133,10 @@
         [
             "GEOGCS[",
             '"wgs84",',
    -        'DATUM["WGS_1984",SPHEROID["wgs84",6378137,298.257223563],TOWGS84[0.000000,0.000000,0.000000]],',
    +        (
    +            'DATUM["WGS_1984",SPHEROID["wgs84",6378137,298.257223563],TOWGS84[0.000000,'
    +            "0.000000,0.000000]],"
    +        ),
             'PRIMEM["Greenwich",0],',
             'UNIT["degree",0.0174532925199433]',
             "]",
    diff --git a/scripts/r.in.wms/r.in.wms.py b/scripts/r.in.wms/r.in.wms.py
    index dccfc8e3517..cc571dbd878 100755
    --- a/scripts/r.in.wms/r.in.wms.py
    +++ b/scripts/r.in.wms/r.in.wms.py
    @@ -264,7 +264,8 @@ def main():
                 if "GRASS" in options["driver"]:
                     grass.warning(
                         _(
    -                        "The proxy will be ignored by the chosen GRASS driver. It is only used with the GDAL driver."
    +                        "The proxy will be ignored by the chosen GRASS driver. It is "
    +                        "only used with the GDAL driver."
                         )
                     )
     
    diff --git a/scripts/r.in.wms/srs.py b/scripts/r.in.wms/srs.py
    index 43ee8747eb2..460e3c14fc1 100644
    --- a/scripts/r.in.wms/srs.py
    +++ b/scripts/r.in.wms/srs.py
    @@ -1,5 +1,6 @@
     """!
    -@brief WMS, WMTS and NASA OnEarth drivers implemented in GRASS using GDAL Python bindings.
    +@brief WMS, WMTS and NASA OnEarth drivers implemented in GRASS using GDAL Python
    +bindings.
     
     List of classes:
      - srs.py::Srs
    @@ -9,8 +10,10 @@
     This program is free software under the GNU General Public License
     (>=v2). Read the file COPYING that comes with GRASS for details.
     
    -@author Stepan Turek  (Based on code from OWSLib - Copyright below)
    +@author Stepan Turek  (Based on code from OWSLib - Copyright
    +        below)
     """
    +
     # -*- coding: ISO-8859-15 -*-
     # =============================================================================
     # Copyright (c) 2011 Tom Kralidis
    diff --git a/scripts/r.in.wms/wms_base.py b/scripts/r.in.wms/wms_base.py
    index 56158635d53..b2b74e3e6c6 100644
    --- a/scripts/r.in.wms/wms_base.py
    +++ b/scripts/r.in.wms/wms_base.py
    @@ -1,5 +1,6 @@
     """!
    -@brief Preparation of parameters for drivers, which download it, and managing downloaded data.
    +@brief Preparation of parameters for drivers, which download it, and managing
    +    downloaded data.
     
     List of classes:
      - wms_base::WMSBase
    @@ -108,7 +109,8 @@ def _initializeParameters(self, options, flags):
                 self.params["wms_version"] = "1.3.0"
                 grass.warning(
                     _(
    -                    "WMS version <1.3.0> will be used, because version <1.1.1> does not support <%s>projection"
    +                    "WMS version <1.3.0> will be used, because version <1.1.1> does "
    +                    "not support <%s>projection"
                     )
                     % GetSRSParamVal(self.params["srs"])
                 )
    @@ -130,7 +132,8 @@ def _initializeParameters(self, options, flags):
                 if self.source_epsg != self.target_epsg:
                     grass.warning(
                         _(
    -                        "SRS differences: WMS source EPSG %s != location EPSG %s (use srs=%s to adjust)"
    +                        "SRS differences: WMS source EPSG %s != location EPSG %s (use "
    +                        "srs=%s to adjust)"
                         )
                         % (self.source_epsg, self.target_epsg, self.target_epsg)
                     )
    @@ -173,14 +176,16 @@ def _initializeParameters(self, options, flags):
         def _modifyProj(self, proj):
             """!Modify proj.4 string for usage in this module"""
     
    -        # add +wktext parameter to avoid dropping of +nadgrids parameter (if presented) in gdalwarp
    +        # add +wktext parameter to avoid dropping of +nadgrids parameter (if presented)
    +        # in gdalwarp
             if "+nadgrids=" in proj and " +wktext" not in proj:
                 proj += " +wktext"
     
             return proj
     
         def _checkIgnoeredParams(self, options, flags, driver_props):
    -        """!Write warnings for set parameters and flags, which chosen driver does not use."""
    +        """!Write warnings for set parameters and flags, which chosen driver does not
    +        use."""
     
             not_relevant_params = []
             for i_param in driver_props["ignored_params"]:
    @@ -350,16 +355,20 @@ def _computeBbox(self):
                     grass.fatal(_("Unable to write data into tempfile"))
                 finally:
                     temp_region_opened.close()
    +            try:
    +                points = grass.read_command(
    +                    "m.proj",
    +                    flags="d",
    +                    proj_out=self.proj_srs,
    +                    proj_in=self.proj_location,
    +                    input=temp_region,
    +                    quiet=True,
    +                )  # TODO: stdin
    +            except CalledModuleError:
    +                points = None
    +            finally:
    +                grass.try_remove(temp_region)
     
    -            points = grass.read_command(
    -                "m.proj",
    -                flags="d",
    -                proj_out=self.proj_srs,
    -                proj_in=self.proj_location,
    -                input=temp_region,
    -                quiet=True,
    -            )  # TODO: stdin
    -            grass.try_remove(temp_region)
                 if not points:
                     grass.fatal(_("Unable to determine region, %s failed") % "m.proj")
     
    diff --git a/scripts/r.in.wms/wms_cap_parsers.py b/scripts/r.in.wms/wms_cap_parsers.py
    index 6846124efa3..40a7d63d3af 100644
    --- a/scripts/r.in.wms/wms_cap_parsers.py
    +++ b/scripts/r.in.wms/wms_cap_parsers.py
    @@ -16,6 +16,7 @@
     
     @author Stepan Turek  (Mentor: Martin Landa)
     """
    +
     import pathlib
     
     from xml.etree.ElementTree import ParseError
    @@ -84,7 +85,8 @@ def Ns(self, tag_name):
     class WMSCapabilitiesTree(BaseCapabilitiesTree):
         def __init__(self, cap_file, force_version=None):
             """!Parses WMS capabilities file.
    -            If the capabilities file cannot be parsed if it raises xml.etree.ElementTree.ParseError.
    +            If the capabilities file cannot be parsed if it raises
    +            xml.etree.ElementTree.ParseError.
     
             The class manges inheritance in 'Layer' elements. Inherited elements
             are added to 'Layer' element.
    @@ -200,8 +202,10 @@ def _inhNotSame(self, element_name, cmp_type, layer, parent_layer, add_arg=None)
     
             @param element_name - name of inherited element
             @param cmp_type - 'element_content' - compared value is text of  element
    -        @param cmp_type - 'child_element_content' - compared value is text of a child of the  element
    -        @param cmp_type - 'attribute' - compared value is text of the  element attribute
    +        @param cmp_type - 'child_element_content' - compared value is text of a child
    +                           of the  element
    +        @param cmp_type - 'attribute' - compared value is text of the  element
    +                           attribute
             @param layer -  element which inherits
             @param parent_layer -  element which is inherited from
             @param add_arg - name of child element or attribute
    @@ -309,10 +313,12 @@ def NsOws(self, tag):
     class WMTSCapabilitiesTree(BaseCapabilitiesTree):
         def __init__(self, cap_file):
             """!Parses WMTS capabilities file.
    -            If the capabilities file cannot be parsed it raises xml.etree.ElementTree.ParseError.
    +            If the capabilities file cannot be parsed it raises
    +            xml.etree.ElementTree.ParseError.
     
             The class also removes elements which are in invalid form and are needed
    -        by wxGUI capabilities dialog or for creation of GetTile request by GRASS WMS library.
    +        by wxGUI capabilities dialog or for creation of GetTile request by GRASS WMS
    +        library.
     
             @param cap_file - capabilities file
             """
    @@ -550,7 +556,8 @@ def __init__(self, cap_file):
                 If the file cannot be parsed it raises xml.etree.ElementTree.ParseError.
     
             The class also removes elements which are in invalid form and are needed
    -        by wxGUI capabilities dialog or for creation of GetMap request by GRASS WMS library.
    +        by wxGUI capabilities dialog or for creation of GetMap request by GRASS WMS
    +        library.
     
             @param cap_file - capabilities file
             """
    diff --git a/scripts/r.in.wms/wms_drv.py b/scripts/r.in.wms/wms_drv.py
    index df592624031..51c9f2037c4 100644
    --- a/scripts/r.in.wms/wms_drv.py
    +++ b/scripts/r.in.wms/wms_drv.py
    @@ -1,5 +1,6 @@
     """!
    -@brief WMS, WMTS and NASA OnEarth drivers implemented in GRASS using GDAL Python bindings.
    +@brief WMS, WMTS and NASA OnEarth drivers implemented in GRASS using GDAL Python
    +bindings.
     
     List of classes:
      - wms_drv::WMSDrv
    @@ -26,7 +27,8 @@
     except:
         grass.fatal(
             _(
    -            "Unable to load GDAL Python bindings (requires package 'python-gdal' being installed)"
    +            "Unable to load GDAL Python bindings (requires package 'python-gdal' "
    +            "being installed)"
             )
         )
     
    @@ -103,7 +105,8 @@ def _download(self):
                 # url for request the tile
                 query_url = tile[0]
     
    -            # the tile size and offset in pixels for placing it into raster where tiles are joined
    +            # the tile size and offset in pixels for placing it into raster where tiles
    +            # are joined
                 tile_ref = tile[1]
                 grass.debug(query_url, 2)
                 try:
    @@ -129,8 +132,9 @@ def _download(self):
                     temp_tile_opened = open(temp_tile, "wb")
                     temp_tile_opened.write(wms_data.read())
                 except OSError as e:
    -                # some servers are not happy with many subsequent requests for tiles done immediately,
    -                # if immediate request was unsuccessful, try to repeat the request after 5s and 30s breaks
    +                # some servers are not happy with many subsequent requests for tiles
    +                # done immediately, if immediate request was unsuccessful, try to
    +                # repeat the request after 5s and 30s breaks
                     # TODO probably servers can return more kinds of errors related to this
                     # problem (not only 104)
                     if isinstance(e, socket.error) and e[0] == 104 and fetch_try < 2:
    @@ -143,7 +147,8 @@ def _download(self):
     
                         grass.warning(
                             _(
    -                            "Server refused to send data for a tile.\nRequest will be repeated after %d s."
    +                            "Server refused to send data for a tile.\nRequest will be "
    +                            "repeated after %d s."
                             )
                             % sleep_time
                         )
    @@ -177,7 +182,8 @@ def _download(self):
                 if tile_dataset_info.RasterCount < 1:
                     grass.fatal(
                         _(
    -                        "WMS server error: no band(s) received. Is server URL correct? <%s>"
    +                        "WMS server error: no band(s) received. Is server URL correct? "
    +                        "<%s>"
                         )
                         % server_url
                     )
    @@ -268,7 +274,8 @@ def _download(self):
             return temp_map
     
         def _pct2rgb(self, src_filename, dst_filename):
    -        """!Create new dataset with data in dst_filename with bands according to src_filename
    +        """!Create new dataset with data in dst_filename with bands according to
    +        src_filename
             raster color table - modified code from gdal utility pct2rgb
     
             @return new dataset
    @@ -321,7 +328,8 @@ class BaseRequestMgr:
         """!Base class for request managers."""
     
         def _computeRequestData(self, bbox, tl_corner, tile_span, tile_size, mat_num_bbox):
    -        """!Initialize data needed for iteration through tiles. Used by WMTS_GRASS and OnEarth_GRASS drivers."""
    +        """!Initialize data needed for iteration through tiles. Used by WMTS_GRASS and
    +        OnEarth_GRASS drivers."""
             epsilon = 1e-15
     
             # request data bbox specified in row and col number
    @@ -446,7 +454,8 @@ def __init__(self, params, bbox, region, tile_size, proj_srs, cap_file=None):
     
             proj = params["proj_name"] + "=" + GetSRSParamVal(params["srs"])
             self.url = params["url"] + (
    -            "SERVICE=WMS&REQUEST=GetMap&VERSION=%s&LAYERS=%s&WIDTH=%s&HEIGHT=%s&STYLES=%s&TRANSPARENT=%s"
    +            "SERVICE=WMS&REQUEST=GetMap&VERSION=%s&LAYERS=%s&WIDTH=%s&HEIGHT=%s&"
    +            "STYLES=%s&TRANSPARENT=%s"
                 % (
                     params["wms_version"],
                     params["layers"],
    @@ -511,11 +520,13 @@ def __init__(self, params, bbox, region, tile_size, proj_srs, cap_file=None):
             self.map_region["rows"] = rows
     
         def GetMapRegion(self):
    -        """!Get size in pixels and bounding box of raster where all tiles will be merged."""
    +        """!Get size in pixels and bounding box of raster where all tiles will be
    +        merged."""
             return self.map_region
     
         def GetNextTile(self):
    -        """!Get url for tile request from server and information for merging the tile with other tiles"""
    +        """!Get url for tile request from server and information for merging the tile
    +        with other tiles"""
     
             tile_ref = {}
     
    @@ -636,7 +647,8 @@ def __init__(self, params, bbox, region, proj_srs, cap_file=None):
                 mat_set.findall(self.xml_ns.NsWmts("TileMatrix")), region, bbox
             )
     
    -        # get extend of data available on server expressed in max/min rows and cols of tile matrix
    +        # get extend of data available on server expressed in max/min rows and cols of
    +        # tile matrix
             mat_num_bbox = self._getMatSize(tile_mat, mat_set_link)
     
             # initialize data needed for iteration through tiles
    @@ -645,11 +657,13 @@ def __init__(self, params, bbox, region, proj_srs, cap_file=None):
             )
     
         def GetMapRegion(self):
    -        """!Get size in pixels and bounding box of raster where all tiles will be merged."""
    +        """!Get size in pixels and bounding box of raster where all tiles will be
    +        merged."""
             return self.map_region
     
         def _getMatSets(self, root, layer_name, srs):
    -        """!Get matrix sets which are available for chosen layer and have required EPSG."""
    +        """!Get matrix sets which are available for chosen layer and have required
    +        EPSG."""
     
             contents = root.find(self.xml_ns.NsWmts("Contents"))
             layers = contents.findall(self.xml_ns.NsWmts("Layer"))
    @@ -731,7 +745,8 @@ def _findTileMats(self, tile_mats, region, bbox):
             return best_t_mat
     
         def _getMetersPerUnit(self):
    -        """!Get coefficient which allows converting units of request projection into meters."""
    +        """!Get coefficient which allows converting units of request projection into
    +        meters."""
             if self.meters_per_unit:
                 return self.meters_per_unit
     
    @@ -760,7 +775,8 @@ def _getMetersPerUnit(self):
             return self.meters_per_unit
     
         def _getMatSize(self, tile_mat, mat_set_link):
    -        """!Get rows and cols extend of data available on server for chosen layer and tile matrix."""
    +        """!Get rows and cols extend of data available on server for chosen layer and
    +        tile matrix."""
     
             # general tile matrix size
             mat_num_bbox = {}
    @@ -817,7 +833,8 @@ def _computeRequestData(self, tile_mat, params, bbox, mat_num_bbox, mat_set_srs)
             tl_corner["minx"] = float(tl_str[0])
             tl_corner["maxy"] = float(tl_str[1])
     
    -        # TODO do it more generally WMS cap parser may use it in future(not needed now)???
    +        # TODO do it more generally WMS cap parser may use it in future(not needed
    +        #  now)???
             s = Srs(
                 mat_set_srs
             )  # NOTE not used params['srs'], it is just number, encoding needed
    @@ -858,7 +875,8 @@ def _computeRequestData(self, tile_mat, params, bbox, mat_num_bbox, mat_set_srs)
             )
     
         def GetNextTile(self):
    -        """!Get url for tile request from server and information for merging the tile with other tiles."""
    +        """!Get url for tile request from server and information for merging the tile
    +        with other tiles."""
             if not self.intersects or self.i_col > self.t_num_bbox["max_col"]:
                 return None
     
    @@ -905,7 +923,8 @@ def __init__(self, params, bbox, region, proj_srs, tile_service):
             self._computeRequestData(bbox, t_patt_bbox, self.tile_span, self.tile_size)
     
         def GetMapRegion(self):
    -        """!Get size in pixels and bounding box of raster where all tiles will be merged."""
    +        """!Get size in pixels and bounding box of raster where all tiles will be
    +        merged."""
             return self.map_region
     
         def _parseTileService(self, root, bbox, region, params):
    @@ -1011,7 +1030,8 @@ def _parseTilePattern(self, group_t_patts, bbox, region):
     
         def _insTimeToTilePatternUrl(self, url_params, urls):
             """!Time can be variable in some urls in OnEarth TMS.
    -        Insert requested time from 'urlparams' into the variable if any url of urls contains the variable.
    +        Insert requested time from 'urlparams' into the variable if any url of urls
    +        contains the variable.
             """
             url = None
             not_sup_params = []
    @@ -1055,7 +1075,8 @@ def _insTimeToTilePatternUrl(self, url_params, urls):
             if not_sup_params:
                 grass.warning(
                     _(
    -                    "%s driver supports only '%s' parameter in '%s'. Other parameters are ignored."
    +                    "%s driver supports only '%s' parameter in '%s'. Other parameters "
    +                    "are ignored."
                     )
                     % ("OnEarth GRASS", "time", "urlparams")
                 )
    @@ -1080,7 +1101,8 @@ def _computeRequestData(self, bbox, t_patt_bbox, tile_span, tile_size):
             )
     
         def GetNextTile(self):
    -        """!Get url for tile request from server and information for merging the tile with other tiles"""
    +        """!Get url for tile request from server and information for merging the tile
    +        with other tiles"""
             if self.i_col > self.t_num_bbox["max_col"]:
                 return None
     
    diff --git a/scripts/r.in.wms/wms_gdal_drv.py b/scripts/r.in.wms/wms_gdal_drv.py
    index 479318e4f4f..353de1a679c 100644
    --- a/scripts/r.in.wms/wms_gdal_drv.py
    +++ b/scripts/r.in.wms/wms_gdal_drv.py
    @@ -20,7 +20,8 @@
     except:
         grass.fatal(
             _(
    -            "Unable to load GDAL Python bindings (requires package 'python-gdal' being installed)"
    +            "Unable to load GDAL Python bindings (requires package 'python-gdal' being "
    +            "installed)"
             )
         )
     
    @@ -144,7 +145,8 @@ def _download(self):
                 grass.warning(
                     _(
                         "If module will not be able to fetch the data in this "
    -                    + "geographic projection, \n try 'WMS_GRASS' driver or use WMS version 1.1.1."
    +                    "geographic projection, \n try 'WMS_GRASS' driver or use WMS "
    +                    "version 1.1.1."
                     )
                 )
     
    diff --git a/scripts/r.mapcalc.simple/testsuite/test_rmapcalcsimple.py b/scripts/r.mapcalc.simple/testsuite/test_rmapcalcsimple.py
    index 70da5f40b11..d400ccc7980 100644
    --- a/scripts/r.mapcalc.simple/testsuite/test_rmapcalcsimple.py
    +++ b/scripts/r.mapcalc.simple/testsuite/test_rmapcalcsimple.py
    @@ -8,6 +8,7 @@
                 License (>=v2). Read the file COPYING that comes with GRASS
                 for details.
     """
    +
     from grass.gunittest.case import TestCase
     
     
    diff --git a/scripts/r.mask/r.mask.py b/scripts/r.mask/r.mask.py
    index e33788dffc1..969c35ad9d4 100755
    --- a/scripts/r.mask/r.mask.py
    +++ b/scripts/r.mask/r.mask.py
    @@ -122,7 +122,8 @@ def main():
                 if not grass.overwrite():
                     grass.fatal(
                         _(
    -                        "MASK already found in current mapset. Delete first or overwrite."
    +                        "MASK already found in current mapset. Delete first or "
    +                        "overwrite."
                         )
                     )
                 else:
    diff --git a/scripts/r.reclass.area/r.reclass.area.py b/scripts/r.reclass.area/r.reclass.area.py
    index 8809ccb042e..9e579eb5f10 100755
    --- a/scripts/r.reclass.area/r.reclass.area.py
    +++ b/scripts/r.reclass.area/r.reclass.area.py
    @@ -180,7 +180,8 @@ def reclass(inf, outf, lim, clump, diag, les):
     def rmarea(infile, outfile, thresh, coef):
         # transform user input from hectares to map units (kept this for future)
         # thresh = thresh * 10000.0 / (float(coef)**2)
    -    # grass.debug("Threshold: %d, coeff linear: %s, coef squared: %d" % (thresh, coef, (float(coef)**2)), 0)
    +    # grass.debug("Threshold: %d, coeff linear: %s, coef squared: %d" %
    +    # (thresh, coef, (float(coef)**2)), 0)
     
         # transform user input from hectares to meters because currently v.clean
         # rmarea accept only meters as threshold
    diff --git a/scripts/r.reclass.area/testsuite/testrra.py b/scripts/r.reclass.area/testsuite/testrra.py
    index 6c7822c0f6c..e6e2300875b 100644
    --- a/scripts/r.reclass.area/testsuite/testrra.py
    +++ b/scripts/r.reclass.area/testsuite/testrra.py
    @@ -8,6 +8,7 @@
     	            License (>=v2). Read the file COPYING that comes with GRASS
     	            for details.
     """
    +
     from grass.gunittest.case import TestCase
     from grass.gunittest.main import test
     
    diff --git a/scripts/r.tileset/r.tileset.py b/scripts/r.tileset/r.tileset.py
    index 240a0911d58..13e970aeaab 100644
    --- a/scripts/r.tileset/r.tileset.py
    +++ b/scripts/r.tileset/r.tileset.py
    @@ -333,15 +333,17 @@ def main():
     
         # Find the skewedness of the two directions.
         # Define it to be greater than one
    -    # In the direction (x or y) in which the world is least skewed (ie north south in lat long)
    -    # Divide the world into strips. These strips are as big as possible constrained by max_
    +    # In the direction (x or y) in which the world is least skewed (ie north south in
    +    #   lat long)
    +    # Divide the world into strips. These strips are as big as possible constrained by
    +    #   max_
         # In the other direction do the same thing.
         # There's some recomputation of the size of the world that's got to come in
         # here somewhere.
     
    -    # For now, however, we are going to go ahead and request more data than is necessary.
    -    # For small regions far from the critical areas of projections this makes very little difference
    -    # in the amount of data gotten.
    +    # For now, however, we are going to go ahead and request more data than is
    +    # necessary. For small regions far from the critical areas of projections this
    +    # makes very little difference in the amount of data gotten.
         # We can make this efficient for big regions or regions near critical
         # points later.
     
    diff --git a/scripts/r.unpack/r.unpack.py b/scripts/r.unpack/r.unpack.py
    index 8ec8cdcba48..a19123b28f0 100644
    --- a/scripts/r.unpack/r.unpack.py
    +++ b/scripts/r.unpack/r.unpack.py
    @@ -30,8 +30,8 @@
     # %end
     # %flag
     # % key: o
    -# % label: Override projection check (use current location's projection)
    -# % description: Assume that the dataset has same projection as the current location
    +# % label: Override projection check (use current projects's CRS)
    +# % description: Assume that the dataset has same coordinate reference system as the current project
     # % guisection: Output settings
     # %end
     # %flag
    @@ -140,9 +140,7 @@ def main():
         # check projection compatibility in a rather crappy way
     
         if flags["o"]:
    -        grass.warning(
    -            _("Overriding projection check (using current location's projection).")
    -        )
    +        grass.warning(_("Overriding projection check (using current project's CRS)."))
     
         else:
             diff_result_1 = diff_result_2 = None
    @@ -155,7 +153,8 @@ def main():
                 if os.path.exists(proj_info_file_2):
                     grass.fatal(
                         _(
    -                        "PROJ_INFO file is missing, unpack raster map in XY (unprojected) location."
    +                        "PROJ_INFO file is missing, unpack raster map in XY "
    +                        "(unprojected) project."
                         )
                     )
                 skip_projection_check = True  # XY location
    @@ -179,22 +178,23 @@ def main():
                         grass.warning(
                             _(
                                 "Difference between PROJ_INFO file of packed map "
    -                            "and of current location:\n{diff}"
    +                            "and of current project:\n{diff}"
                             ).format(diff="".join(diff_result_1))
                         )
                     if diff_result_2:
                         grass.warning(
                             _(
                                 "Difference between PROJ_UNITS file of packed map "
    -                            "and of current location:\n{diff}"
    +                            "and of current project:\n{diff}"
                             ).format(diff="".join(diff_result_2))
                         )
                     grass.fatal(
                         _(
    -                        "Projection of dataset does not appear to match current location."
    -                        " In case of no significant differences in the projection definitions,"
    +                        "Coordinate reference system of dataset does"
    +                        " not appear to match current project."
    +                        " In case of no significant differences in the CRS definitions,"
                             " use the -o flag to ignore them and use"
    -                        " current location definition."
    +                        " current project definition."
                         )
                     )
     
    diff --git a/scripts/v.db.renamecolumn/v.db.renamecolumn.py b/scripts/v.db.renamecolumn/v.db.renamecolumn.py
    index 87f1850a57c..edcd89c0935 100755
    --- a/scripts/v.db.renamecolumn/v.db.renamecolumn.py
    +++ b/scripts/v.db.renamecolumn/v.db.renamecolumn.py
    @@ -63,7 +63,8 @@ def main():
         if not table:
             grass.fatal(
                 _(
    -                "There is no table connected to the input vector map. Cannot rename any column"
    +                "There is no table connected to the input vector map. Cannot rename "
    +                "any column"
                 )
             )
     
    @@ -75,7 +76,8 @@ def main():
             if len(newcol) > 10:
                 grass.fatal(
                     _(
    -                    "Column name <%s> too long. The DBF driver supports column names not longer than 10 characters"
    +                    "Column name <%s> too long. The DBF driver supports column names "
    +                    "not longer than 10 characters"
                     )
                     % newcol
                 )
    @@ -83,7 +85,8 @@ def main():
         if oldcol == keycol:
             grass.fatal(
                 _(
    -                "Cannot rename column <%s> as it is needed to keep table <%s> connected to the input vector map"
    +                "Cannot rename column <%s> as it is needed to keep table <%s> "
    +                "connected to the input vector map"
                 )
                 % (oldcol, table)
             )
    diff --git a/scripts/v.dissolve/v.dissolve.py b/scripts/v.dissolve/v.dissolve.py
    index c0700c4eebf..b5e030ad573 100755
    --- a/scripts/v.dissolve/v.dissolve.py
    +++ b/scripts/v.dissolve/v.dissolve.py
    @@ -362,7 +362,8 @@ def create_or_check_result_columns_or_fatal(
                                 "Result column '{column}' needs a type "
                                 "specified (using the syntax: 'name type') "
                                 "when no methods are provided with the "
    -                            "{option_name} option and aggregation backend is '{backend}'"
    +                            "{option_name} option and aggregation backend is "
    +                            "'{backend}'"
                             ).format(
                                 column=column,
                                 option_name="aggregate_methods",
    @@ -586,7 +587,8 @@ def main():
         if not column:
             gs.warning(
                 _(
    -                "No '%s' option specified. Dissolving based on category values from layer <%s>."
    +                "No '%s' option specified. Dissolving based on category values from "
    +                "layer <%s>."
                 )
                 % ("column", layer)
             )
    diff --git a/scripts/v.import/v.import.html b/scripts/v.import/v.import.html
    index 072b92e5529..a530f5f3662 100644
    --- a/scripts/v.import/v.import.html
    +++ b/scripts/v.import/v.import.html
    @@ -64,46 +64,6 @@ 

    EXAMPLE

    v.import input=research_area.shp output=research_area extent=input
    -

    ERROR MESSAGES

    - -

    SQL syntax errors

    - -Depending on the currently selected SQL driver, error messages such as follows may arise: - -
    -DBMI-SQLite driver error:
    -Error in sqlite3_prepare():
    -near "ORDER": syntax error
    -
    - -Or: - -
    -DBMI-DBF driver error:
    -SQL parser error:
    -syntax error, unexpected DESC, expecting NAME processing 'DESC
    -
    - -This indicates that a column name in the input dataset corresponds to a reserved -SQL word (here: 'ORDER' and 'DESC' respectively). A different column name has to be -used in this case. The columns parameter can be used to assign different -column names on the fly in order to avoid using reserved SQL words. - -For a list of SQL reserved words for SQLite (the default driver), -see here. - -

    Projection errors

    - -
    -Projection of dataset does not appear to match the current project.
    -
    - -Here you need to create or use a project whose CRS matches that -of the vector data you wish to import. Try using location parameter to -create a new project based upon the CRS information in the file. If -desired, you can then re-project it to another project -with v.proj. -

    SEE ALSO

    diff --git a/scripts/v.import/v.import.py b/scripts/v.import/v.import.py index 809c18243bd..8bb95fa8737 100755 --- a/scripts/v.import/v.import.py +++ b/scripts/v.import/v.import.py @@ -269,7 +269,8 @@ def main(): except: grass.fatal( _( - "Unable to load GDAL Python bindings (requires package 'python-gdal' being installed)" + "Unable to load GDAL Python bindings (requires package " + "'python-gdal' being installed)" ) ) if int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(2, 4, 1): @@ -345,7 +346,8 @@ def main(): except: grass.fatal( _( - "Unable to load GDAL Python bindings (requires package 'python-gdal' being installed)" + "Unable to load GDAL Python bindings (requires package " + "'python-gdal' being installed)" ) ) if int(gdal.VersionInfo("VERSION_NUM")) < GDAL_COMPUTE_VERSION(2, 4, 1): diff --git a/scripts/v.in.geonames/v.in.geonames.py b/scripts/v.in.geonames/v.in.geonames.py index 401cca5c134..5a5653c2157 100755 --- a/scripts/v.in.geonames/v.in.geonames.py +++ b/scripts/v.in.geonames/v.in.geonames.py @@ -59,7 +59,8 @@ def main(): if dbfdriver: grass.warning( _( - "Since DBF driver is used, the content of the 'alternatenames' column might be cut with respect to the original Geonames.org column content" + "Since DBF driver is used, the content of the 'alternatenames' column " + "might be cut with respect to the original Geonames.org column content" ) ) diff --git a/scripts/v.rast.stats/testsuite/test_v_rast_stats.py b/scripts/v.rast.stats/testsuite/test_v_rast_stats.py index 4b411bf6666..ca3111d14d8 100644 --- a/scripts/v.rast.stats/testsuite/test_v_rast_stats.py +++ b/scripts/v.rast.stats/testsuite/test_v_rast_stats.py @@ -2,6 +2,7 @@ @author Soeren Gebbert """ + from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule from grass.pygrass.vector import VectorTopo diff --git a/scripts/v.rast.stats/v.rast.stats.py b/scripts/v.rast.stats/v.rast.stats.py index cea37e38cca..c5a288a749d 100644 --- a/scripts/v.rast.stats/v.rast.stats.py +++ b/scripts/v.rast.stats/v.rast.stats.py @@ -133,7 +133,8 @@ def main(): except KeyError: grass.fatal( _( - "There is no table connected to this map. Run v.db.connect or v.db.addtable first." + "There is no table connected to this map. Run v.db.connect or " + "v.db.addtable first." ) ) # we need this for non-DBF driver: diff --git a/scripts/v.report/v.report.py b/scripts/v.report/v.report.py index f5284f97bf7..80ece04aeb5 100755 --- a/scripts/v.report/v.report.py +++ b/scripts/v.report/v.report.py @@ -141,8 +141,8 @@ def main(): grass.fatal( _( "There is a table connected to input vector map '%s', but " - "there are no categories present in the key column '%s'. Consider using " - "v.to.db to correct this." + "there are no categories present in the key column '%s'. " + "Consider using v.to.db to correct this." ) % (mapname, f["key"]) ) diff --git a/scripts/v.unpack/v.unpack.py b/scripts/v.unpack/v.unpack.py index c55432316ce..bd350676444 100644 --- a/scripts/v.unpack/v.unpack.py +++ b/scripts/v.unpack/v.unpack.py @@ -32,8 +32,8 @@ # %end # %flag # % key: o -# % label: Override projection check (use current location's projection) -# % description: Assume that the dataset has same projection as the current location +# % label: Override projection check (use current projects's CRS) +# % description: Assume that the dataset has same coordinate reference system as the current project # % guisection: Output settings # %end # %flag @@ -154,7 +154,8 @@ def main(): if os.path.exists(loc_proj): grass.fatal( _( - "PROJ_INFO file is missing, unpack vector map in XY (unprojected) location." + "PROJ_INFO file is missing, unpack vector map in XY (unprojected) " + "project." ) ) skip_projection_check = True # XY location @@ -185,22 +186,23 @@ def main(): grass.warning( _( "Difference between PROJ_INFO file of packed map " - "and of current location:\n{diff}" + "and of current project:\n{diff}" ).format(diff="".join(diff_result_1)) ) if diff_result_2: grass.warning( _( "Difference between PROJ_UNITS file of packed map " - "and of current location:\n{diff}" + "and of current project:\n{diff}" ).format(diff="".join(diff_result_2)) ) grass.fatal( _( - "Projection of dataset does not appear to match current location." - " In case of no significant differences in the projection definitions," + "Coordinate reference system of dataset does not" + " appear to match current project." + " In case of no significant differences in the CRS definitions," " use the -o flag to ignore them and use" - " current location definition." + " current project definition." ) ) diff --git a/singularity/debian/README_debian.md b/singularity/debian/README_debian.md index 824986042b9..2f1e287873d 100644 --- a/singularity/debian/README_debian.md +++ b/singularity/debian/README_debian.md @@ -16,7 +16,7 @@ cd grass __Build the singularity with__: ```bash -sudo singularity build grass_development.simg singularity/debian/singularity_debian +sudo singularity build grass_gis.simg singularity/debian/singularity_debian ``` __To build a stable version__: @@ -24,17 +24,17 @@ __To build a stable version__: change to the releasebranch or tag you want to build: ```bash -git checkout remotes/origin/releasebranch_8_2 +git checkout {tag or branch} ``` and build and enter with: ```bash -sudo singularity build grass_8_2.simg singularity/debian/singularity_debian +sudo singularity build grass_gis.simg singularity/debian/singularity_debian ``` The image can be used as: ```bash -singularity exec containers/grass_8.2.simg grass --version +singularity exec containers/grass_gis.simg grass --version ``` diff --git a/temporal/CMakeLists.txt b/temporal/CMakeLists.txt new file mode 100644 index 00000000000..eb62bacb0c1 --- /dev/null +++ b/temporal/CMakeLists.txt @@ -0,0 +1,57 @@ +set(temporal_DIRS + t.create + t.copy + t.support + t.topology + t.list + t.info + t.merge + t.upgrade + t.remove + t.sample + t.register + t.unregister + t.rast.accumulate + t.rast.accdetect + t.rast.aggregate + t.rast.aggregate.ds + t.rast.colors + t.rast.contour + t.rast.to.rast3 + t.rast.univar + t.rast.list + t.rast.mapcalc + t.rast.algebra + t.rast.neighbors + t.rast.series + t.rast.export + t.rast.out.vtk + t.rast.import + t.rast.gapfill + t.rast.extract + t.rast.to.vect + t.rast.what + t.rast3d.list + t.rast3d.extract + t.rast3d.mapcalc + t.rast3d.algebra + t.rast3d.univar + t.rename + t.select + t.snap + t.shift + t.vect.list + t.vect.db.select + t.vect.export + t.vect.extract + t.vect.algebra + t.vect.import + t.vect.what.strds + t.vect.observe.strds + t.vect.univar) + +build_program_in_subdir(t.connect DEPENDS grass_gis grass_temporal) + +foreach(temporal_DIR ${temporal_DIRS}) + build_script_in_subdir(${temporal_DIR}) +endforeach() diff --git a/temporal/t.info/t.info.py b/temporal/t.info/t.info.py index 24faee35940..dd86e8123ef 100755 --- a/temporal/t.info/t.info.py +++ b/temporal/t.info/t.info.py @@ -79,7 +79,7 @@ def main(): if system and not shellstyle and not history: # 0123456789012345678901234567890 print( - " +------------------- Temporal DBMI backend information ----------------------+" + " +------------------- Temporal DBMI backend information ----------------------+" # noqa: E501 ) print(" | DBMI Python interface:...... " + str(dbif.get_dbmi().__name__)) print(" | Temporal database string:... " + str(tgis.get_tgis_database_string())) @@ -88,7 +88,7 @@ def main(): for row in rows: print(" | %s .......... %s" % (row[0], row[1])) print( - " +----------------------------------------------------------------------------+" + " +----------------------------------------------------------------------------+" # noqa: E501 ) return elif system and not history: diff --git a/temporal/t.list/t.list.py b/temporal/t.list/t.list.py index 26be3c9b453..7f8de190a45 100755 --- a/temporal/t.list/t.list.py +++ b/temporal/t.list/t.list.py @@ -143,14 +143,16 @@ def main(): if issubclass(sp.__class__, tgis.AbstractMapDataset): sys.stderr.write( _( - "Time stamped %s maps with %s available in mapset <%s>:\n" + "Time stamped %s maps with %s available in mapset " + "<%s>:\n" ) % (sp.get_type(), time, key) ) else: sys.stderr.write( _( - "Space time %s datasets with %s available in mapset <%s>:\n" + "Space time %s datasets with %s available in " + "mapset <%s>:\n" ) % (sp.get_new_map_instance(None).get_type(), time, key) ) diff --git a/temporal/t.rast.accdetect/t.rast.accdetect.py b/temporal/t.rast.accdetect/t.rast.accdetect.py index 39d9826b6ad..b8cee70fda4 100644 --- a/temporal/t.rast.accdetect/t.rast.accdetect.py +++ b/temporal/t.rast.accdetect/t.rast.accdetect.py @@ -429,14 +429,18 @@ def main(): elif i > 0 and i < num_maps - 1: prev_map = occurrence_maps[map.next().get_id()].get_name() next_map = occurrence_maps[map.prev().get_id()].get_name() - # In case the previous map is null() set null() or the start indicator + # In case the previous map is null() set null() or the start + # indicator subexpr1 = "if(isnull(%s), null(), %i)" % ( curr_map, indicator_start, ) - # In case the previous map was not null() if the current map is null() set null() - # if the current map is not null() and the next map is not null() set - # intermediate indicator, if the next map is null set the end indicator + # In case the previous map was not null() if the current map is + # null() set null() + # if the current map is not null() and the next map is not + # null() set + # intermediate indicator, if the next map is null set the end + # indicator subexpr2 = "if(isnull(%s), %i, %i)" % ( next_map, indicator_end, @@ -467,14 +471,18 @@ def main(): elif i > 0 and i < num_maps - 1: prev_map = occurrence_maps[map.prev().get_id()].get_name() next_map = occurrence_maps[map.next().get_id()].get_name() - # In case the previous map is null() set null() or the start indicator + # In case the previous map is null() set null() or the start + # indicator subexpr1 = "if(isnull(%s), null(), %i)" % ( curr_map, indicator_start, ) - # In case the previous map was not null() if the current map is null() set null() - # if the current map is not null() and the next map is not null() set - # intermediate indicator, if the next map is null set the end indicator + # In case the previous map was not null() if the current map + # is null() set null() + # if the current map is not null() and the next map is not + # null() set + # intermediate indicator, if the next map is null set the end + # indicator subexpr2 = "if(isnull(%s), %i, %i)" % ( next_map, indicator_end, diff --git a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py index 2056a654f7c..c5eb4618d92 100644 --- a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py +++ b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py @@ -7,6 +7,7 @@ :authors: Soeren Gebbert """ + import os import grass.pygrass.modules as pymod import grass.temporal as tgis diff --git a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute_parallel.py b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute_parallel.py index f70c150c7c0..ac6471398ad 100644 --- a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute_parallel.py +++ b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute_parallel.py @@ -7,6 +7,7 @@ :authors: Soeren Gebbert """ + import os import grass.pygrass.modules as pymod import grass.temporal as tgis diff --git a/temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py b/temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py index 265d4f82465..fe53844feea 100644 --- a/temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py +++ b/temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py @@ -7,6 +7,7 @@ :authors: Soeren Gebbert """ + import os import grass.pygrass.modules as pymod import grass.temporal as tgis diff --git a/temporal/t.rast.algebra/t.rast.algebra.py b/temporal/t.rast.algebra/t.rast.algebra.py index 8f1718f6795..0bb81453f0a 100644 --- a/temporal/t.rast.algebra/t.rast.algebra.py +++ b/temporal/t.rast.algebra/t.rast.algebra.py @@ -108,9 +108,10 @@ def main(): except ImportError: grass.script.fatal( _( - "Please install PLY (Lex and Yacc Python implementation) to use the temporal algebra modules. " - "You can use t.rast.mapcalc that provides a limited but useful alternative to " - "t.rast.algebra without PLY requirement." + "Please install PLY (Lex and Yacc Python implementation) to use the " + "temporal algebra modules. You can use t.rast.mapcalc that provides a " + "limited but useful alternative to t.rast.algebra without PLY " + "requirement." ) ) diff --git a/temporal/t.rast.list/t.rast.list.py b/temporal/t.rast.list/t.rast.list.py index a28a80f5455..5278cc60f82 100755 --- a/temporal/t.rast.list/t.rast.list.py +++ b/temporal/t.rast.list/t.rast.list.py @@ -155,7 +155,8 @@ def main(): excluded_option_name="separator", excluded_option_value=separator, reason=_( - "A standard CSV separator (delimiter) is only one character long" + "A standard CSV separator (delimiter) is only one character " + "long" ), ) ) @@ -221,7 +222,8 @@ def main(): excluded_option_name="columns", excluded_option_value=columns, reason=_( - "Column '{name}' is not available with the method '{method}'" + "Column '{name}' is not available with the method " + "'{method}'" ).format(name=column, method=method), ) ) @@ -236,7 +238,8 @@ def main(): excluded_option_name="columns", excluded_option_value=columns, reason=_( - "Column '{name}' is not available with the method '{method}'" + "Column '{name}' is not available with the method " + "'{method}'" ).format(name=column, method=method), ) ) diff --git a/temporal/t.rast.series/t.rast.series.py b/temporal/t.rast.series/t.rast.series.py index f78f71b5ab6..2ec781dfab8 100755 --- a/temporal/t.rast.series/t.rast.series.py +++ b/temporal/t.rast.series/t.rast.series.py @@ -148,9 +148,8 @@ def main(): if len(rows) > max_files_open: grass.warning( _( - "Processing over {} maps: activating -z flag of r.series which slows down processing.".format( - max_files_open - ) + "Processing over {} maps: activating -z flag of r.series which " + "slows down processing.".format(max_files_open) ) ) flag += "z" diff --git a/temporal/t.rast.series/testsuite/test_series.py b/temporal/t.rast.series/testsuite/test_series.py index 4eb41f80f1a..7b9df7921b7 100644 --- a/temporal/t.rast.series/testsuite/test_series.py +++ b/temporal/t.rast.series/testsuite/test_series.py @@ -7,6 +7,7 @@ :authors: Soeren Gebbert """ + import os import grass.pygrass.modules as pymod import grass.temporal as tgis diff --git a/temporal/t.rast.what/t.rast.what.py b/temporal/t.rast.what/t.rast.what.py index 45a0c9347b2..ffb1c884893 100755 --- a/temporal/t.rast.what/t.rast.what.py +++ b/temporal/t.rast.what/t.rast.what.py @@ -160,7 +160,9 @@ def main(options, flags): if not coordinates and not points and not use_stdin: gscript.fatal( _( - "Please specify the coordinates, the points option or use the 'i' flag to pipe coordinate positions to t.rast.what from stdin, to provide the sampling coordinates" + "Please specify the coordinates, the points option or use the 'i' flag " + "to pipe coordinate positions to t.rast.what from stdin, to provide " + "the sampling coordinates" ) ) @@ -552,7 +554,7 @@ def one_point_per_timerow_output( x|y|1991-01-01 00:00:00;1991-01-02 00:00:00|1991-01-02 00:00:00;1991-01-03 00:00:00|1991-01-03 00:00:00;1991-01-04 00:00:00|1991-01-04 00:00:00;1991-01-05 00:00:00 3730731.49590371|5642483.51236521|6|8|7|7 3581249.04638104|5634411.97526282|5|8|7|7 - """ + """ # noqa: E501 out_file = open(output, "w") if output != "-" else sys.stdout matrix = [] diff --git a/temporal/t.rast3d.algebra/t.rast3d.algebra.py b/temporal/t.rast3d.algebra/t.rast3d.algebra.py index 0e39bb45a59..2d80e90a9db 100644 --- a/temporal/t.rast3d.algebra/t.rast3d.algebra.py +++ b/temporal/t.rast3d.algebra/t.rast3d.algebra.py @@ -94,9 +94,10 @@ def main(): except ImportError: grass.script.fatal( _( - "Please install PLY (Lex and Yacc Python implementation) to use the temporal algebra modules. " - "You can use t.rast3d.mapcalc that provides a limited but useful alternative to " - "t.rast3d.mapcalc2 without PLY requirement." + "Please install PLY (Lex and Yacc Python implementation) to use the " + "temporal algebra modules. You can use t.rast3d.mapcalc that provides " + "a limited but useful alternative to t.rast3d.mapcalc2 without PLY " + "requirement." ) ) diff --git a/temporal/t.rast3d.algebra/testsuite/test_raster3d_algebra.py b/temporal/t.rast3d.algebra/testsuite/test_raster3d_algebra.py index 59d47a1dacd..980ec553119 100644 --- a/temporal/t.rast3d.algebra/testsuite/test_raster3d_algebra.py +++ b/temporal/t.rast3d.algebra/testsuite/test_raster3d_algebra.py @@ -7,7 +7,6 @@ :authors: Soeren Gebbert and Thomas Leppelt """ - import grass.script import grass.temporal as tgis from grass.gunittest.case import TestCase diff --git a/temporal/t.select/t.select.py b/temporal/t.select/t.select.py index 030aba99c7e..bf7d0f0e53a 100644 --- a/temporal/t.select/t.select.py +++ b/temporal/t.select/t.select.py @@ -75,7 +75,8 @@ def main(): except ImportError: grass.fatal( _( - "Please install PLY (Lex and Yacc Python implementation) to use the temporal algebra modules." + "Please install PLY (Lex and Yacc Python implementation) to use the " + "temporal algebra modules." ) ) diff --git a/temporal/t.shift/testsuite/test_shift.py b/temporal/t.shift/testsuite/test_shift.py index 1c1f29f03d9..eff9a5f5702 100644 --- a/temporal/t.shift/testsuite/test_shift.py +++ b/temporal/t.shift/testsuite/test_shift.py @@ -7,6 +7,7 @@ :authors: Soeren Gebbert """ + import os import grass.pygrass.modules as pymod import grass.temporal as tgis diff --git a/temporal/t.snap/testsuite/test_snap.py b/temporal/t.snap/testsuite/test_snap.py index e16acc52a57..5d8c0bbe166 100644 --- a/temporal/t.snap/testsuite/test_snap.py +++ b/temporal/t.snap/testsuite/test_snap.py @@ -7,6 +7,7 @@ :authors: Soeren Gebbert """ + import os import grass.pygrass.modules as pymod import grass.temporal as tgis diff --git a/temporal/t.support/testsuite/test_support_str3ds.py b/temporal/t.support/testsuite/test_support_str3ds.py index 4e2a1d30123..613b5e9bbc3 100644 --- a/temporal/t.support/testsuite/test_support_str3ds.py +++ b/temporal/t.support/testsuite/test_support_str3ds.py @@ -7,6 +7,7 @@ :authors: Soeren Gebbert """ + import os import grass.pygrass.modules as pymod import grass.temporal as tgis diff --git a/temporal/t.support/testsuite/test_support_strds.py b/temporal/t.support/testsuite/test_support_strds.py index a618f94bc5b..40692693c34 100644 --- a/temporal/t.support/testsuite/test_support_strds.py +++ b/temporal/t.support/testsuite/test_support_strds.py @@ -7,6 +7,7 @@ :authors: Soeren Gebbert """ + import os import grass.pygrass.modules as pymod import grass.temporal as tgis diff --git a/temporal/t.support/testsuite/test_support_stvds.py b/temporal/t.support/testsuite/test_support_stvds.py index 256e3a9b98f..2cd973c2119 100644 --- a/temporal/t.support/testsuite/test_support_stvds.py +++ b/temporal/t.support/testsuite/test_support_stvds.py @@ -7,6 +7,7 @@ :authors: Soeren Gebbert """ + import os import grass.pygrass.modules as pymod import grass.temporal as tgis diff --git a/temporal/t.topology/t.topology.py b/temporal/t.topology/t.topology.py index f531e096099..9f795aa0840 100755 --- a/temporal/t.topology/t.topology.py +++ b/temporal/t.topology/t.topology.py @@ -88,7 +88,7 @@ def main(): # 0123456789012345678901234567890 print( - " +-------------------- Temporal topology -------------------------------------+" + " +-------------------- Temporal topology -------------------------------------+" # noqa: E501 ) if where: print(" | Is subset of dataset: ...... True") @@ -124,7 +124,7 @@ def main(): print(" | Granularity: ............... %s" % str(gran)) print( - " +-------------------- Topological relations ---------------------------------+" + " +-------------------- Topological relations ---------------------------------+" # noqa: E501 ) dict_ = sp.count_temporal_relations(maps) @@ -158,7 +158,7 @@ def main(): if key == "precedes": print(" | Precedes: .................. %s" % (dict_[key])) print( - " +----------------------------------------------------------------------------+" + "+----------------------------------------------------------------------------+" # noqa: E501 ) diff --git a/temporal/t.unregister/testsuite/test_unregister.py b/temporal/t.unregister/testsuite/test_unregister.py index 6cf54e482e2..fa011b9edaa 100644 --- a/temporal/t.unregister/testsuite/test_unregister.py +++ b/temporal/t.unregister/testsuite/test_unregister.py @@ -7,6 +7,7 @@ :authors: Soeren Gebbert """ + import os import grass.pygrass.modules as pymod import grass.temporal as tgis diff --git a/temporal/t.vect.algebra/t.vect.algebra.py b/temporal/t.vect.algebra/t.vect.algebra.py index 763a50ef6e9..b68ef19f9a1 100644 --- a/temporal/t.vect.algebra/t.vect.algebra.py +++ b/temporal/t.vect.algebra/t.vect.algebra.py @@ -73,7 +73,8 @@ def main(): except ImportError: grass.script.fatal( _( - "Please install PLY (Lex and Yacc Python implementation) to use the temporal algebra modules." + "Please install PLY (Lex and Yacc Python implementation) to use the " + "temporal algebra modules." ) ) diff --git a/temporal/t.vect.observe.strds/t.vect.observe.strds.py b/temporal/t.vect.observe.strds/t.vect.observe.strds.py index 996392239ae..9b01ca08cef 100755 --- a/temporal/t.vect.observe.strds/t.vect.observe.strds.py +++ b/temporal/t.vect.observe.strds/t.vect.observe.strds.py @@ -104,7 +104,8 @@ def main(): if len(strds_names) != len(column_names): grass.fatal( _( - "The number of columns must be equal to the number of space time raster datasets" + "The number of columns must be equal to the number of space time " + "raster datasets" ) ) @@ -149,7 +150,8 @@ def main(): grass.fatal( _( "Temporal type of space time raster datasets must be equal\n" - "<%(a)s> of type %(type_a)s do not match <%(b)s> of type %(type_b)s" + "<%(a)s> of type %(type_a)s do not match <%(b)s> of type " + "%(type_b)s" % { "a": first_strds.get_id(), "type_a": first_strds.get_temporal_type(), diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt new file mode 100644 index 00000000000..63f821d0e76 --- /dev/null +++ b/utils/CMakeLists.txt @@ -0,0 +1,40 @@ +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/mkhtml.py + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/generate_last_commit_file.py + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +set(current_time_s_ms_SRCS "timer/main.c") +if(MSVC) + list(APPEND current_time_s_ms_SRCS "timer/msvc/gettimeofday.c") +endif() +build_program_in_subdir( + timer + NAME + current_time_s_ms + DEPENDS + grass_gis + SOURCES + "${current_time_s_ms_SRCS}" + RUNTIME_OUTPUT_DIR + etc) + +build_program( + NAME + g.echo + SOURCES + g.echo.c + RUNTIME_OUTPUT_DIR + utils + PACKAGE + "NONE") +add_dependencies(g.echo python_doc_utils) +add_custom_target( + python_doc_utils + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/mkhtml.py + ${GISBASE}/utils + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/g.html2man/g.html2man.py ${GISBASE}/utils + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/g.html2man/ghtml.py ${GISBASE}/utils + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/g.html2man/ggroff.py ${GISBASE}/utils) diff --git a/utils/mkrest.py b/utils/mkrest.py index a5320ef2d01..ca04c173f51 100755 --- a/utils/mkrest.py +++ b/utils/mkrest.py @@ -36,7 +36,7 @@ :doc:`Main Page ` - :doc:`${INDEXNAMECAP} index <${INDEXNAME}>` - :doc:`Full index ` 2003-${YEAR} `GRASS Development Team `_ -""" +""" # noqa: E501 ) footer_noindex = string.Template( diff --git a/utils/timer/main.c b/utils/timer/main.c index 72a1f9c3813..38fe0926b0b 100644 --- a/utils/timer/main.c +++ b/utils/timer/main.c @@ -12,8 +12,13 @@ * for details. * *****************************************************************************/ - +#ifdef _MSC_VER +#include +#include +#else #include +#endif + #include #include diff --git a/vector/CMakeLists.txt b/vector/CMakeLists.txt new file mode 100644 index 00000000000..6128938a713 --- /dev/null +++ b/vector/CMakeLists.txt @@ -0,0 +1,252 @@ +build_program_in_subdir(v.buffer DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.build DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.build.polylines DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.category DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.class DEPENDS grass_gis grass_vector grass_arraystats) + +build_program_in_subdir(v.clean DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.cluster DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.colors DEPENDS grass_gis grass_vector grass_raster3d) + +build_program_in_subdir(v.colors.out DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.db.connect DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.db.select DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.decimate DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.delaunay DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.distance DEPENDS grass_gis grass_vector grass_gmath) + +build_program_in_subdir(v.drape DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.edit DEPENDS grass_gis grass_vector grass_vedit) + +build_program_in_subdir(v.extract DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.extrude DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.generalize DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.hull DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.info DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.in.ascii DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.in.db DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.in.dxf DEPENDS grass_gis grass_vector) + +file(GLOB v_in_pdal_SOURCES "v.in.pdal/*.c" "v.in.pdal/main.cpp") +build_program_in_subdir( + v.in.pdal + SOURCES + "${v_in_pdal_SOURCES}" + DEPENDS + grass_gis + grass_vector + PRIMARY_DEPENDS + PDAL) + +build_program_in_subdir(v.in.region DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.kcv DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.kernel DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.label DEPENDS grass_gis grass_vector grass_display) + +build_program_in_subdir(v.label.sa DEPENDS grass_gis grass_vector grass_display) + +build_program_in_subdir(v.proj DEPENDS grass_gis grass_vector grass_gproj) + +build_program_in_subdir(v.profile DEPENDS grass_gis grass_vector) + +add_subdirectory(v.lrs) + +build_program_in_subdir(v.mkgrid DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.neighbors DEPENDS grass_gis grass_vector grass_stats) + +build_program_in_subdir(v.net DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.net.alloc DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.net.allpairs DEPENDS grass_gis grass_vector + grass_neta) + +build_program_in_subdir(v.net.bridge DEPENDS grass_gis grass_vector grass_neta) + +build_program_in_subdir(v.net.centrality DEPENDS grass_gis grass_vector + grass_neta) + +build_program_in_subdir(v.net.components DEPENDS grass_gis grass_vector + grass_neta) + +build_program_in_subdir(v.net.connectivity DEPENDS grass_gis grass_vector + grass_neta) + +build_program_in_subdir(v.net.distance DEPENDS grass_gis grass_vector + grass_neta) + +build_program_in_subdir(v.net.flow DEPENDS grass_gis grass_vector grass_neta) + +build_program_in_subdir(v.net.iso DEPENDS grass_gis grass_vector grass_neta) + +build_program_in_subdir(v.net.path DEPENDS grass_gis grass_vector grass_neta) + +build_program_in_subdir(v.net.salesman DEPENDS grass_gis grass_vector + grass_neta) + +build_program_in_subdir(v.net.spanningtree DEPENDS grass_gis grass_vector + grass_neta) + +build_program_in_subdir(v.net.steiner DEPENDS grass_gis grass_vector grass_neta) + +build_program_in_subdir(v.net.timetable DEPENDS grass_gis grass_vector + grass_neta) + +build_program_in_subdir(v.net.visibility DEPENDS grass_gis grass_vector + grass_neta) + +build_program_in_subdir(v.normal DEPENDS grass_gis grass_vector grass_cdhc) + +build_program_in_subdir(v.out.ascii DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.out.dxf DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.out.pov DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.out.svg DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.out.vtk DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.outlier DEPENDS grass_gis grass_vector grass_lidar) + +build_program_in_subdir(v.overlay DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.parallel DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.patch DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.perturb DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.split DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.qcount DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.random DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.reclass DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.rectify DEPENDS grass_gis grass_vector grass_imagery) + +build_program_in_subdir(v.sample DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.segment DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.select DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.support DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.surf.bspline DEPENDS grass_gis grass_vector + grass_lidar grass_gpde) + +build_program_in_subdir(v.surf.idw DEPENDS grass_gis grass_vector) + +build_program_in_subdir( + v.surf.rst + DEPENDS + grass_gis + grass_vector + grass_interpdata + grass_interpfl + grass_qtree + OPTIONAL_DEPENDS + OPENMP) + +build_program_in_subdir(v.transform DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.timestamp DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.to.3d DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.to.db DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.to.points DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.to.rast DEPENDS grass_gis grass_vector grass_raster) + +build_program_in_subdir(v.to.rast3 DEPENDS grass_gis grass_vector + grass_raster3d) + +build_program_in_subdir(v.type DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.univar DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.voronoi DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.what DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.what.rast DEPENDS grass_gis grass_vector grass_raster) + +build_program_in_subdir(v.what.rast3 DEPENDS grass_gis grass_vector + grass_raster3d) + +build_program_in_subdir(v.vect.stats DEPENDS grass_gis grass_vector grass_stats) + +build_program_in_subdir(v.vol.rst DEPENDS grass_gis grass_vector grass_raster3d + grass_bitmap) + +build_program_in_subdir(v.out.ogr DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.in.ogr DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.external DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.external.out DEPENDS grass_gis grass_vector) + +build_program_in_subdir(v.in.lidar DEPENDS grass_gis grass_vector + PRIMARY_DEPENDS LIBLAS) + +build_program_in_subdir( + v.lidar.correction + DEPENDS + grass_gis + grass_vector + grass_lidar + PRIMARY_DEPENDS + LIBLAS) + +build_program_in_subdir( + v.lidar.edgedetection + DEPENDS + grass_gis + grass_vector + grass_lidar + grass_dbmibase + grass_gmath + PRIMARY_DEPENDS + LIBLAS) + +build_program_in_subdir(v.lidar.growing DEPENDS grass_gis grass_vector + PRIMARY_DEPENDS LIBLAS) + +build_program_in_subdir(v.out.lidar DEPENDS grass_gis grass_vector + PRIMARY_DEPENDS LIBLAS) + +build_program_in_subdir(v.out.postgis DEPENDS grass_gis grass_vector + PRIMARY_DEPENDS POSTGRES) + +if(WITH_OPENDWG) + build_program_in_subdir(v.in.dwg DEPENDS grass_gis grass_vector) +endif() diff --git a/vector/v.external/args.c b/vector/v.external/args.c index 798982f2c15..7f482f836e6 100644 --- a/vector/v.external/args.c +++ b/vector/v.external/args.c @@ -46,9 +46,10 @@ void parse_args(int argc, char **argv, struct _options *options, flags->override = G_define_flag(); flags->override->key = 'o'; flags->override->label = - _("Override projection check (use current location's projection)"); - flags->override->description = _("Assume that the dataset has the same " - "projection as the current location"); + _("Override projection check (use current project's CRS)"); + flags->override->description = + _("Assume that the dataset has the same " + "coordinate reference system as the current project"); flags->proj = G_define_flag(); flags->proj->key = 'j'; diff --git a/vector/v.external/proj.c b/vector/v.external/proj.c index b1eae407c35..625482fee5e 100644 --- a/vector/v.external/proj.c +++ b/vector/v.external/proj.c @@ -163,15 +163,15 @@ void check_projection(struct Cell_head *cellhd, GDALDatasetH hDS, int layer, /* do not create a xy location because this can mean that the * real SRS has not been recognized or is missing */ if (proj_trouble) { - G_fatal_error(_("Unable to convert input map projection to GRASS " - "format; cannot create new location.")); + G_fatal_error(_("Unable to convert input map CRS to GRASS " + "format; cannot create new project.")); } else { if (0 != G_make_location_crs(outloc, cellhd, proj_info, proj_units, srid, wkt)) { - G_fatal_error(_("Unable to create new location <%s>"), outloc); + G_fatal_error(_("Unable to create new project <%s>"), outloc); } - G_message(_("Location <%s> created"), outloc); + G_message(_("Project <%s> created"), outloc); G_unset_window(); /* new location, projection, and window */ G_get_window(cellhd); @@ -232,14 +232,15 @@ void check_projection(struct Cell_head *cellhd, GDALDatasetH hDS, int layer, proj_info, proj_units)) != 1) { int i_value; - strcpy(error_msg, _("Projection of dataset does not" - " appear to match current location.\n\n")); + strcpy(error_msg, + _("Coordinate reference system of dataset does not" + " appear to match current project.\n\n")); /* TODO: output this info sorted by key: */ if (loc_wind.proj != cellhd->proj || err != -2) { /* error in proj_info */ if (loc_proj_info != NULL) { - strcat(error_msg, _("Location PROJ_INFO is:\n")); + strcat(error_msg, _("Project PROJ_INFO is:\n")); for (i_value = 0; i_value < loc_proj_info->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", @@ -248,22 +249,22 @@ void check_projection(struct Cell_head *cellhd, GDALDatasetH hDS, int layer, strcat(error_msg, "\n"); } else { - strcat(error_msg, _("Location PROJ_INFO is:\n")); + strcat(error_msg, _("Project PROJ_INFO is:\n")); if (loc_wind.proj == PROJECTION_XY) sprintf(error_msg + strlen(error_msg), - "Location proj = %d (unreferenced/unknown)\n", + "Project proj = %d (unreferenced/unknown)\n", loc_wind.proj); else if (loc_wind.proj == PROJECTION_LL) sprintf(error_msg + strlen(error_msg), - "Location proj = %d (lat/long)\n", + "Project proj = %d (lat/long)\n", loc_wind.proj); else if (loc_wind.proj == PROJECTION_UTM) sprintf(error_msg + strlen(error_msg), - "Location proj = %d (UTM), zone = %d\n", + "Project proj = %d (UTM), zone = %d\n", loc_wind.proj, cellhd->zone); else sprintf(error_msg + strlen(error_msg), - "Location proj = %d (unknown), zone = %d\n", + "Project proj = %d (unknown), zone = %d\n", loc_wind.proj, cellhd->zone); } @@ -337,7 +338,7 @@ void check_projection(struct Cell_head *cellhd, GDALDatasetH hDS, int layer, else { /* error in proj_units */ if (loc_proj_units != NULL) { - strcat(error_msg, "Location PROJ_UNITS is:\n"); + strcat(error_msg, "Project PROJ_UNITS is:\n"); for (i_value = 0; i_value < loc_proj_units->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", @@ -355,13 +356,14 @@ void check_projection(struct Cell_head *cellhd, GDALDatasetH hDS, int layer, } } if (!check_only) { - strcat(error_msg, _("\nIn case of no significant differences " - "in the projection definitions," - " use the -o flag to ignore them and use" - " current location definition.\n")); - strcat(error_msg, _("Consider generating a new location from " + strcat(error_msg, + _("\nIn case of no significant differences " + "in the coordinate reference system definitions," + " use the -o flag to ignore them and use" + " current project definition.\n")); + strcat(error_msg, _("Consider generating a new project from " "the input dataset using " - "the 'location' parameter.\n")); + "the 'project' parameter.\n")); } if (check_only) @@ -379,8 +381,8 @@ void check_projection(struct Cell_head *cellhd, GDALDatasetH hDS, int layer, msg_fn = G_message; else msg_fn = G_verbose_message; - msg_fn(_("Projection of input dataset and current location " - "appear to match")); + msg_fn(_("Coordinate reference system of input dataset and current " + "project appear to match")); if (check_only) { GDALClose(hDS); exit(EXIT_SUCCESS); diff --git a/vector/v.extract/testsuite/test_v_extract.py b/vector/v.extract/testsuite/test_v_extract.py index ff0c8b590a3..d266e8ad649 100644 --- a/vector/v.extract/testsuite/test_v_extract.py +++ b/vector/v.extract/testsuite/test_v_extract.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + import os from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/vector/v.fill.holes/examples.ipynb b/vector/v.fill.holes/examples.ipynb index 28d86332b0a..fcc006501e4 100644 --- a/vector/v.fill.holes/examples.ipynb +++ b/vector/v.fill.holes/examples.ipynb @@ -82,7 +82,7 @@ "outputs": [], "source": [ "!g.region vector=data grow=3 res=1\n", - "text_position = (75,5)" + "text_position = (75, 5)" ] }, { @@ -144,7 +144,7 @@ "source": [ "!g.region vector=dissolve_data grow=2 res=1\n", "\n", - "text_position = (75,5)\n", + "text_position = (75, 5)\n", "\n", "plot = gj.Map(use_region=True, width=700)\n", "plot.d_background(color=\"white\")\n", @@ -209,7 +209,7 @@ "plot = gj.Map(use_region=True, width=700)\n", "plot.d_background(color=\"white\")\n", "plot.d_vect(map=\"lakes_only\", legend_label=\"Original\")\n", - "plot.d_legend_vect(flags=\"b\", at=(60,10))\n", + "plot.d_legend_vect(flags=\"b\", at=(60, 10))\n", "plot.show()" ] }, @@ -231,7 +231,7 @@ "plot = gj.Map(use_region=True, width=700)\n", "plot.d_background(color=\"white\")\n", "plot.d_vect(map=\"lakes_filled\", legend_label=\"Filled\")\n", - "plot.d_legend_vect(flags=\"b\", at=(60,10))\n", + "plot.d_legend_vect(flags=\"b\", at=(60, 10))\n", "plot.show()" ] }, @@ -253,7 +253,7 @@ "plot = gj.Map(use_region=True, width=700)\n", "plot.d_background(color=\"white\")\n", "plot.d_vect(map=\"lakes_dissolved\", legend_label=\"Dissolved\")\n", - "plot.d_legend_vect(flags=\"b\", at=(60,10))\n", + "plot.d_legend_vect(flags=\"b\", at=(60, 10))\n", "plot.show()" ] }, @@ -265,9 +265,17 @@ "source": [ "plot = gj.Map(use_region=True, width=1024)\n", "plot.d_background(color=\"#E28A2B\")\n", - "plot.d_vect(map=\"lakes_filled\", color=\"none\", fill_color=\"#384C6B\", legend_label=\"Filled\")\n", - "plot.d_vect(map=\"lakes_only\", color=\"#859BBA\", fill_color=\"none\", width=2, legend_label=\"Original\")\n", - "plot.d_legend_vect(flags=\"b\", at=(80,85), fontsize=22, symbol_size=35)\n", + "plot.d_vect(\n", + " map=\"lakes_filled\", color=\"none\", fill_color=\"#384C6B\", legend_label=\"Filled\"\n", + ")\n", + "plot.d_vect(\n", + " map=\"lakes_only\",\n", + " color=\"#859BBA\",\n", + " fill_color=\"none\",\n", + " width=2,\n", + " legend_label=\"Original\",\n", + ")\n", + "plot.d_legend_vect(flags=\"b\", at=(80, 85), fontsize=22, symbol_size=35)\n", "filename = \"v_fill_holes.png\"\n", "plot.save(filename)\n", "!mogrify -trim {filename}\n", diff --git a/vector/v.in.lidar/main.c b/vector/v.in.lidar/main.c index 76bc0ef540e..8db7d1e3ee6 100644 --- a/vector/v.in.lidar/main.c +++ b/vector/v.in.lidar/main.c @@ -270,10 +270,10 @@ int main(int argc, char *argv[]) limit_opt->guisection = _("Decimation"); outloc_opt = G_define_option(); - outloc_opt->key = "location"; + outloc_opt->key = "project"; outloc_opt->type = TYPE_STRING; outloc_opt->required = NO; - outloc_opt->description = _("Name for new location to create"); + outloc_opt->description = _("Name for new project (location) to create"); outloc_opt->key_desc = "name"; print_flag = G_define_flag(); @@ -319,15 +319,16 @@ int main(int argc, char *argv[]) over_flag = G_define_flag(); over_flag->key = 'o'; over_flag->label = - _("Override projection check (use current location's projection)"); - over_flag->description = _( - "Assume that the dataset has same projection as the current location"); + _("Override projection check (use current project's CRS)"); + over_flag->description = + _("Assume that the dataset has the same coordinate reference system as " + "the current project"); no_import_flag = G_define_flag(); no_import_flag->key = 'i'; - no_import_flag->description = _( - "Create the location specified by the \"location\" parameter and exit." - " Do not import the vector data."); + no_import_flag->description = + _("Create the project specified by the \"project\" parameter and exit." + " Do not import the vector data."); no_import_flag->suppress_required = YES; G_option_exclusive(skip_opt, preserve_opt, NULL); @@ -512,16 +513,16 @@ int main(int argc, char *argv[]) * assume the user has a terminal open */ if (GPJ_wkt_to_grass(&cellhd, &proj_info, &proj_units, projstr, 0) < 0) { - G_fatal_error(_("Unable to convert input map projection to GRASS " - "format; cannot create new location.")); + G_fatal_error(_("Unable to convert input map CRS to GRASS " + "format; cannot create new project.")); } else { if (0 != G_make_location(outloc_opt->answer, &cellhd, proj_info, proj_units)) { - G_fatal_error(_("Unable to create new location <%s>"), + G_fatal_error(_("Unable to create new project <%s>"), outloc_opt->answer); } - G_message(_("Location <%s> created"), outloc_opt->answer); + G_message(_("Project <%s> created"), outloc_opt->answer); } /* If the i flag is set, clean up? and exit here */ @@ -529,7 +530,7 @@ int main(int argc, char *argv[]) exit(EXIT_SUCCESS); /* TODO: */ - G_warning("Import into new location not yet implemented"); + G_warning("Import into new project not yet implemented"); /* at this point the module should be using G_create_alt_env() to change context to the newly created location; once done it should switch back with G_switch_env(). See r.in.gdal */ diff --git a/vector/v.in.lidar/projection.c b/vector/v.in.lidar/projection.c index 44dc7c680d3..ab1b4a7fcd4 100644 --- a/vector/v.in.lidar/projection.c +++ b/vector/v.in.lidar/projection.c @@ -27,13 +27,13 @@ void projection_mismatch_report(struct Cell_head cellhd, int i_value; char error_msg[8192]; - strcpy(error_msg, _("Projection of dataset does not" - " appear to match current location.\n\n")); + strcpy(error_msg, _("Coordinate reference system of dataset does not" + " appear to match current project.\n\n")); /* TODO: output this info sorted by key: */ if (loc_wind.proj != cellhd.proj || err != -2) { if (loc_proj_info != NULL) { - strcat(error_msg, _("GRASS LOCATION PROJ_INFO is:\n")); + strcat(error_msg, _("GRASS project PROJ_INFO is:\n")); for (i_value = 0; i_value < loc_proj_info->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", loc_proj_info->key[i_value], @@ -68,7 +68,7 @@ void projection_mismatch_report(struct Cell_head cellhd, } else { if (loc_proj_units != NULL) { - strcat(error_msg, "GRASS LOCATION PROJ_UNITS is:\n"); + strcat(error_msg, "GRASS project PROJ_UNITS is:\n"); for (i_value = 0; i_value < loc_proj_units->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", loc_proj_units->key[i_value], @@ -84,12 +84,12 @@ void projection_mismatch_report(struct Cell_head cellhd, } } sprintf(error_msg + strlen(error_msg), - _("\nIn case of no significant differences in the projection " - "definitions," + _("\nIn case of no significant differences" + " in the coordinate reference system definitions," " use the -o flag to ignore them and use" - " current location definition.\n")); + " current project definition.\n")); strcat(error_msg, - _("Consider generating a new location with 'location' parameter" + _("Consider generating a new project with 'project' parameter" " from input data set.\n")); G_fatal_error("%s", error_msg); } @@ -130,7 +130,8 @@ void projection_check_wkt(struct Cell_head cellhd, struct Cell_head loc_wind, loc_proj_units, proj_info, proj_units, err); } else if (verbose) { - G_message(_("Projection of input dataset and current location " - "appear to match")); + G_message(_( + "Coordinate reference system of input dataset and current project " + "appear to match")); } } diff --git a/vector/v.in.lidar/v.in.lidar.html b/vector/v.in.lidar/v.in.lidar.html index 04c76c0e281..72177b9f5ed 100644 --- a/vector/v.in.lidar/v.in.lidar.html +++ b/vector/v.in.lidar/v.in.lidar.html @@ -91,7 +91,7 @@

    Project Creation

    If the user wishes to import the data with the full CRS definition, it is possible to have v.in.lidar automatically create a new project based on the CRS and extents of the file being read. This is accomplished -by passing the name to be used for the new project via the location +by passing the name to be used for the new project via the project parameter. Upon completion of the command, a new project will have been created (with only a PERMANENT mapset), and the vector map will have been imported with the indicated output name into the PERMANENT mapset. @@ -116,7 +116,7 @@

    EXAMPLE

    v.in.lidar -p input="Serpent Mound Model LAS Data.las" # create a project with CRS information of the LAS data - v.in.lidar -i input="Serpent Mound Model LAS Data.las" location=Serpent_Mound + v.in.lidar -i input="Serpent Mound Model LAS Data.las" project=Serpent_Mound # quit and restart GRASS in the newly created project "Serpent_Mound" # real import of LiDAR LAS data, without topology and without attribute table diff --git a/vector/v.in.ogr/testsuite/test_v_in_ogr.py b/vector/v.in.ogr/testsuite/test_v_in_ogr.py index 7257c44b0ee..167cd8747e8 100644 --- a/vector/v.in.ogr/testsuite/test_v_in_ogr.py +++ b/vector/v.in.ogr/testsuite/test_v_in_ogr.py @@ -2,6 +2,7 @@ @author Markus Neteler """ + from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/vector/v.in.ogr/v.in.ogr.html b/vector/v.in.ogr/v.in.ogr.html index 91f0cdf5ac2..3a461969663 100644 --- a/vector/v.in.ogr/v.in.ogr.html +++ b/vector/v.in.ogr/v.in.ogr.html @@ -452,7 +452,7 @@

    Projection errors

    Here you need to create or use a project whose CRS matches that -of the vector data you wish to import. Try using location parameter to +of the vector data you wish to import. Try using project parameter to create a new project based upon the CRS information in the file. If desired, you can then reproject it to another project with v.proj. diff --git a/vector/v.in.pdal/main.cpp b/vector/v.in.pdal/main.cpp index 9348463ecc3..0f48e1d5fea 100644 --- a/vector/v.in.pdal/main.cpp +++ b/vector/v.in.pdal/main.cpp @@ -212,19 +212,20 @@ int main(int argc, char *argv[]) Flag *reproject_flag = G_define_flag(); reproject_flag->key = 'w'; reproject_flag->label = - _("Reproject to location's coordinate system if needed"); + _("Reproject to projects's coordinate system if needed"); reproject_flag->description = _("Reprojects input dataset to the coordinate system of" - " the GRASS location (by default only datasets with the" + " the GRASS project (by default only datasets with the" " matching coordinate system can be imported"); reproject_flag->guisection = _("Projection"); Flag *over_flag = G_define_flag(); over_flag->key = 'o'; over_flag->label = - _("Override projection check (use current location's projection)"); - over_flag->description = _( - "Assume that the dataset has same projection as the current location"); + _("Override projection check (use current project's CRS)"); + over_flag->description = + _("Assume that the dataset has the same coordinate reference system as " + "the current project"); over_flag->guisection = _("Projection"); // TODO: from the API it seems that also prj file path and proj string will @@ -347,7 +348,7 @@ int main(int argc, char *argv[]) // we reproject when requested regardless the input projection if (reproject_flag->answer) { - G_message(_("Reprojecting the input to the location projection")); + G_message(_("Reprojecting the input to the project's CRS")); char *proj_wkt = location_projection_as_wkt(false); pdal::Options o4; // TODO: try catch for user input error @@ -370,8 +371,8 @@ int main(int argc, char *argv[]) // getting projection is possible only after prepare if (over_flag->answer) { G_important_message(_("Overriding projection check and assuming" - " that the projection of input matches" - " the location projection")); + " that the CRS of input matches" + " the project's CRS")); } else if (!reproject_flag->answer) { pdal::SpatialReference spatial_reference = diff --git a/vector/v.in.pdal/projection.c b/vector/v.in.pdal/projection.c index 244ee323afb..e1c79a599b0 100644 --- a/vector/v.in.pdal/projection.c +++ b/vector/v.in.pdal/projection.c @@ -27,13 +27,13 @@ void projection_mismatch_report(struct Cell_head cellhd, int i_value; char error_msg[8192]; - strcpy(error_msg, _("Projection of dataset does not" - " appear to match current location.\n\n")); + strcpy(error_msg, _("Coordinate reference system of the dataset does not" + " appear to match current project.\n\n")); /* TODO: output this info sorted by key: */ if (loc_wind.proj != cellhd.proj || err != -2) { if (loc_proj_info != NULL) { - strcat(error_msg, _("GRASS LOCATION PROJ_INFO is:\n")); + strcat(error_msg, _("GRASS project PROJ_INFO is:\n")); for (i_value = 0; i_value < loc_proj_info->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", loc_proj_info->key[i_value], @@ -68,7 +68,7 @@ void projection_mismatch_report(struct Cell_head cellhd, } else { if (loc_proj_units != NULL) { - strcat(error_msg, "GRASS LOCATION PROJ_UNITS is:\n"); + strcat(error_msg, "GRASS project PROJ_UNITS is:\n"); for (i_value = 0; i_value < loc_proj_units->nitems; i_value++) sprintf(error_msg + strlen(error_msg), "%s: %s\n", loc_proj_units->key[i_value], @@ -84,12 +84,12 @@ void projection_mismatch_report(struct Cell_head cellhd, } } sprintf(error_msg + strlen(error_msg), - _("\nIn case of no significant differences in the projection " - "definitions," + _("\nIn case of no significant differences" + " in the coordinate reference system definitions," " use the -o flag to ignore them and use" - " current location definition.\n")); + " current project definition.\n")); strcat(error_msg, - _("Consider generating a new location with 'location' parameter" + _("Consider generating a new project with 'project' parameter" " from input data set.\n")); G_fatal_error("%s", error_msg); } @@ -131,8 +131,8 @@ void projection_check_wkt(struct Cell_head cellhd, struct Cell_head loc_wind, } else { if (verbose) { - G_message(_("Projection of input dataset and current location " - "appear to match")); + G_message(_("Coordinate reference system of the input dataset and " + "current project appear to match")); } } } diff --git a/vector/v.lrs/CMakeLists.txt b/vector/v.lrs/CMakeLists.txt new file mode 100644 index 00000000000..90a0619b96e --- /dev/null +++ b/vector/v.lrs/CMakeLists.txt @@ -0,0 +1,17 @@ +build_library_in_subdir( + lib + NAME + grass_lrs + DEPENDS + grass_gis + grass_vector + HEADERS + "lrs.h") +add_dependencies(grass_lrs db.drivers) +build_program_in_subdir(v.lrs.create DEPENDS grass_lrs) + +build_program_in_subdir(v.lrs.segment DEPENDS grass_lrs) + +build_program_in_subdir(v.lrs.label DEPENDS grass_lrs) + +build_program_in_subdir(v.lrs.where DEPENDS grass_lrs) diff --git a/vector/v.net.alloc/main.c b/vector/v.net.alloc/main.c index 6cf7a4341e6..1d0a6165c3a 100644 --- a/vector/v.net.alloc/main.c +++ b/vector/v.net.alloc/main.c @@ -143,7 +143,7 @@ int main(int argc, char **argv) geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = - _("Use geodesic calculation for longitude-latitude locations"); + _("Use geodesic calculation for longitude-latitude projects"); ucat_f = G_define_flag(); ucat_f->key = 'u'; diff --git a/vector/v.net.allpairs/main.c b/vector/v.net.allpairs/main.c index a1390307e32..d3b78db4633 100644 --- a/vector/v.net.allpairs/main.c +++ b/vector/v.net.allpairs/main.c @@ -109,7 +109,7 @@ int main(int argc, char *argv[]) geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = - _("Use geodesic calculation for longitude-latitude locations"); + _("Use geodesic calculation for longitude-latitude projects"); /* options and flags parser */ if (G_parser(argc, argv)) diff --git a/vector/v.net.centrality/main.c b/vector/v.net.centrality/main.c index fc1abc0ee27..64e4c996507 100644 --- a/vector/v.net.centrality/main.c +++ b/vector/v.net.centrality/main.c @@ -185,7 +185,7 @@ int main(int argc, char *argv[]) geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = - _("Use geodesic calculation for longitude-latitude locations"); + _("Use geodesic calculation for longitude-latitude projects"); add_f = G_define_flag(); add_f->key = 'a'; diff --git a/vector/v.net.distance/main.c b/vector/v.net.distance/main.c index 6344ea65bf7..71e7d05e966 100644 --- a/vector/v.net.distance/main.c +++ b/vector/v.net.distance/main.c @@ -158,7 +158,7 @@ int main(int argc, char *argv[]) geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = - _("Use geodesic calculation for longitude-latitude locations"); + _("Use geodesic calculation for longitude-latitude projects"); segments_f = G_define_flag(); #if 0 diff --git a/vector/v.net.iso/main.c b/vector/v.net.iso/main.c index 47819d196cb..5e711c22823 100644 --- a/vector/v.net.iso/main.c +++ b/vector/v.net.iso/main.c @@ -166,7 +166,7 @@ int main(int argc, char **argv) geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = - _("Use geodesic calculation for longitude-latitude locations"); + _("Use geodesic calculation for longitude-latitude projects"); ucat_f = G_define_flag(); ucat_f->key = 'u'; diff --git a/vector/v.net.path/main.c b/vector/v.net.path/main.c index c2a75c1a0d2..db27395e598 100644 --- a/vector/v.net.path/main.c +++ b/vector/v.net.path/main.c @@ -128,7 +128,7 @@ int main(int argc, char **argv) geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = - _("Use geodesic calculation for longitude-latitude locations"); + _("Use geodesic calculation for longitude-latitude projects"); segments_f = G_define_flag(); segments_f->key = 's'; diff --git a/vector/v.net.salesman/main.c b/vector/v.net.salesman/main.c index 694c6d0c742..c1e26073548 100644 --- a/vector/v.net.salesman/main.c +++ b/vector/v.net.salesman/main.c @@ -206,7 +206,7 @@ int main(int argc, char **argv) geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = - _("Use geodesic calculation for longitude-latitude locations"); + _("Use geodesic calculation for longitude-latitude projects"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); diff --git a/vector/v.net.spanningtree/main.c b/vector/v.net.spanningtree/main.c index cfdd78731b0..f9af1952d41 100644 --- a/vector/v.net.spanningtree/main.c +++ b/vector/v.net.spanningtree/main.c @@ -80,7 +80,7 @@ int main(int argc, char *argv[]) geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = - _("Use geodesic calculation for longitude-latitude locations"); + _("Use geodesic calculation for longitude-latitude projects"); /* options and flags parser */ if (G_parser(argc, argv)) diff --git a/vector/v.net.steiner/main.c b/vector/v.net.steiner/main.c index 9b324136ce2..00a0cd71d77 100644 --- a/vector/v.net.steiner/main.c +++ b/vector/v.net.steiner/main.c @@ -403,7 +403,7 @@ int main(int argc, char **argv) geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = - _("Use geodesic calculation for longitude-latitude locations"); + _("Use geodesic calculation for longitude-latitude projects"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); diff --git a/vector/v.out.postgis/create.c b/vector/v.out.postgis/create.c index 6447024e315..bfff7823279 100644 --- a/vector/v.out.postgis/create.c +++ b/vector/v.out.postgis/create.c @@ -75,7 +75,7 @@ char *create_pgfile(const char *dsn, const char *schema, const char *olink, if (strcmp(tokens[0], "srid") == 0 && (epsg && strcmp(tokens[1], epsg) != 0)) - G_warning(_("EPSG code defined for current location (%s) is " + G_warning(_("EPSG code defined for current project (%s) is " "overridden by %s"), epsg, tokens[1]); diff --git a/vector/v.rectify/env.c b/vector/v.rectify/env.c index 80990ad8bfc..f2d69f64d2a 100644 --- a/vector/v.rectify/env.c +++ b/vector/v.rectify/env.c @@ -35,7 +35,7 @@ int select_target_env(void) int show_env(void) { - fprintf(stderr, "env(%d) switch to LOCATION %s, MAPSET %s\n", which_env, + fprintf(stderr, "env(%d) switch to project %s, mapset %s\n", which_env, G_getenv_nofatal("LOCATION_NAME") == NULL ? "?" : G_getenv_nofatal("LOCATION_NAME"), diff --git a/vector/v.rectify/main.c b/vector/v.rectify/main.c index b91ad5efcbe..b02630c88ae 100644 --- a/vector/v.rectify/main.c +++ b/vector/v.rectify/main.c @@ -202,7 +202,7 @@ int main(int argc, char *argv[]) if (G_find_vector2(out_opt->answer, G_mapset())) { G_warning(_("The vector map <%s> already exists in"), out_opt->answer); - G_warning(_("target LOCATION %s, MAPSET %s:"), G_location(), + G_warning(_("target project %s, mapset %s:"), G_location(), G_mapset()); G_fatal_error(_("Rectification cancelled.")); } diff --git a/vector/v.rectify/target.c b/vector/v.rectify/target.c index e5bf3ce41e6..3714f25866d 100644 --- a/vector/v.rectify/target.c +++ b/vector/v.rectify/target.c @@ -26,7 +26,7 @@ int get_target(char *group) sprintf(buf, "%s/%s", G_gisdbase(), location); if (access(buf, 0) != 0) { - sprintf(buf, _("Target location <%s> not found"), location); + sprintf(buf, _("Target project <%s> not found"), location); goto error; } select_target_env(); @@ -37,7 +37,7 @@ int get_target(char *group) select_current_env(); return 1; } - sprintf(buf, _("Mapset <%s> in target location <%s> - "), mapset, location); + sprintf(buf, _("Mapset <%s> in target project <%s> - "), mapset, location); strcat(buf, stat == 0 ? _("permission denied") : _("not found")); error: strcat(buf, _("Please run i.target for group.")); diff --git a/vector/v.to.rast/testsuite/test_v_to_rast.py b/vector/v.to.rast/testsuite/test_v_to_rast.py index 273c77983d8..352b8c578f3 100644 --- a/vector/v.to.rast/testsuite/test_v_to_rast.py +++ b/vector/v.to.rast/testsuite/test_v_to_rast.py @@ -11,6 +11,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + from grass.gunittest.case import TestCase from grass.gunittest.main import test diff --git a/vector/v.univar/testsuite/v_univar_test.py b/vector/v.univar/testsuite/v_univar_test.py index 3b9c75b7d70..33fd0425c1d 100644 --- a/vector/v.univar/testsuite/v_univar_test.py +++ b/vector/v.univar/testsuite/v_univar_test.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule diff --git a/vector/v.vect.stats/testsuite/test_vect_stats.py b/vector/v.vect.stats/testsuite/test_vect_stats.py index 8d7cf0e6c18..fe982ceff33 100644 --- a/vector/v.vect.stats/testsuite/test_vect_stats.py +++ b/vector/v.vect.stats/testsuite/test_vect_stats.py @@ -8,6 +8,7 @@ License (>=v2). Read the file COPYING that comes with GRASS for details. """ + from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule diff --git a/vector/v.vol.rst/v.vol.rst.html b/vector/v.vol.rst/v.vol.rst.html index 1211c5d4700..36143808772 100644 --- a/vector/v.vol.rst/v.vol.rst.html +++ b/vector/v.vol.rst/v.vol.rst.html @@ -172,10 +172,9 @@

    EXAMPLES

    ### First part: generate synthetic 3D data (true 3D soil data preferred) # generate random positions from elevation map (2D) -r.random elevation.10m vector_output=elevrand n=200 +r.random elevation.10m vector=elevrand n=200 seed=42 # generate synthetic values -v.db.addcolumn elevrand col="x double precision, y double precision" v.to.db elevrand option=coor col=x,y v.db.select elevrand @@ -202,7 +201,7 @@

    EXAMPLES

    v.db.select elevrand_3d # optionally: check 3D points in Paraview -v.out.vtk input=elevrand_3d output=elevrand_3d.vtk type=point dp=2 +v.out.vtk input=elevrand_3d output=elevrand_3d.vtk type=point precision=2 paraview --data=elevrand_3d.vtk ### Second part: 3D interpolation from 3D point data