Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test/base example #190

Merged
merged 28 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f63c45c
Writing some initial tests for Map.py using pytest-qgis
zacdezgeo Jan 3, 2025
05e0e88
Add proper registration of WMS provider
zacdezgeo Jan 3, 2025
e372fe6
wip to test add_layers functionality
zacdezgeo Jan 3, 2025
0352924
Add python env file to use extlibs as pythonpath
alukach Jan 7, 2025
9f2db44
Debug adding provider (wip)
zacdezgeo Jan 7, 2025
088bc52
Base example test implemented
zacdezgeo Jan 8, 2025
b89df26
Update CI to authenticate to earthengine
zacdezgeo Jan 8, 2025
efd43cf
Add test to pythonpath
zacdezgeo Jan 8, 2025
e00ac73
Revert pytest call in CI
zacdezgeo Jan 8, 2025
a839ea9
Add pythonpath
zacdezgeo Jan 8, 2025
85d8717
Simplify test execution in CI (wip)
zacdezgeo Jan 13, 2025
99eeedb
Add future for CI dependencies
zacdezgeo Jan 14, 2025
d9508e8
Reorganized plugin code into a module
zacdezgeo Jan 14, 2025
6926180
Add caching of dependencies and use pre-built qgis image
zacdezgeo Jan 14, 2025
84d9515
Activate virtualenv to avoid system wide permissions error
zacdezgeo Jan 14, 2025
5bbe63c
Update python version to use matrix strategy
zacdezgeo Jan 14, 2025
49ab5db
Update python version to 3.9
zacdezgeo Jan 14, 2025
2a4572a
Remove setup python
zacdezgeo Jan 14, 2025
05e170f
Update base image to Kartoza
zacdezgeo Jan 14, 2025
60c0e0b
Move to qgis/qgis image
zacdezgeo Jan 14, 2025
ba31920
Revert to configuring our own environment
zacdezgeo Jan 14, 2025
d17f75e
Move plugin files to ee_plugin module
zacdezgeo Jan 14, 2025
6246b5b
Modify path for paver package to avoid nested ee_plugin
zacdezgeo Jan 14, 2025
7483124
Add icons, i18n, and contrib to paver packaging
zacdezgeo Jan 14, 2025
c3d71fe
Merge branch 'master' into test/base-example
zacdezgeo Jan 14, 2025
2973d87
Update path to ee_plugin module
zacdezgeo Jan 15, 2025
7cb23ae
Add paver to dev requirements
zacdezgeo Jan 15, 2025
82e9315
Bug 195/add vector layer (#196)
zacdezgeo Jan 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,27 @@ jobs:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up QGIS environment
- name: Set up QGIS environment
run: |
sudo apt update
sudo apt install -y qgis python3-qgis python3-pyqt5 python3-pytest

- name: Set Environment Variables
run: |
echo "QGIS_HOME=/usr" >> $GITHUB_ENV
echo "QT_QPA_PLATFORM=offscreen" >> $GITHUB_ENV
echo "DISPLAY=:99" >> $GITHUB_ENV

- name: Start Virtual Display
run: Xvfb :99 -screen 0 1024x768x24 &

- name: Configure Earth Engine Credentials
run: |
mkdir -p ~/.config/earthengine
echo '${{ secrets.EE_CREDENTIALS_JSON }}' > ~/.config/earthengine/credentials

- name: Install dependencies
run: |
python3 -m pip install --upgrade pip
pip install -r requirements-dev.txt

- name: Run pre-commit checks
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ temp
venv
.DS_Store
htmlcov
.coverage
1 change: 1 addition & 0 deletions .python.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PYTHONPATH=${PYTHONPATH}:./extlibs:/Applications/QGIS-LTR.app/Contents/MacOS/lib/python3.9
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love hardcoding these paths into our repo but I think we can refine that later. These are simply for developer experience so will just be an annoyance for any plugin developers with differing paths.

10 changes: 10 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"python.envFile": "${workspaceFolder}/.python.env",
"terminal.integrated.env.osx": {
"PYTHONPATH": "${PYTHONPATH}:./extlibs:/Applications/QGIS-LTR.app/Contents/MacOS/lib/python3.9"
},
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": [
"test"
],
}
4 changes: 2 additions & 2 deletions Map.py → ee_plugin/Map.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ def addLayer(eeObject, visParams=None, name=None, shown=True, opacity=1.0):
>>> from ee_plugin import Map
>>> Map.addLayer(.....)
"""
from .utils import add_or_update_ee_layer
from . import utils

add_or_update_ee_layer(eeObject, visParams, name, shown, opacity)
utils.add_or_update_ee_layer(eeObject, visParams, name, shown, opacity)


def centerObject(feature, zoom=None):
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions ee_plugin.py → ee_plugin/ee_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction

from ee_plugin import provider

# read the plugin version from metadata
cfg = configparser.ConfigParser()
cfg.read(os.path.join(os.path.dirname(__file__), "metadata.txt"))
Expand All @@ -37,6 +35,8 @@ def __init__(self, iface):
application at run time.
:type iface: QgsInterface
"""
from . import provider

# Save reference to the QGIS interface
self.iface = iface

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions provider.py → ee_plugin/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def __init__(self, *args, **kwargs):

# create WMS provider
self.wms = QgsProviderRegistry.instance().createProvider("wms", *args, **kwargs)
assert self.wms, f"Failed to create WMS provider: {args}, {kwargs}"

@classmethod
def description(cls):
Expand Down
23 changes: 3 additions & 20 deletions utils.py → ee_plugin/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
QgsRectangle,
)

import ee_plugin
from .ee_plugin import VERSION as ee_plugin_version


def get_ee_image_url(image):
Expand All @@ -27,7 +27,6 @@ def get_ee_image_url(image):

def update_ee_layer_properties(layer, eeObject, visParams, shown, opacity):
layer.dataProvider().set_ee_object(eeObject)

layer.setCustomProperty("ee-layer", True)

if opacity is not None:
Expand All @@ -38,7 +37,7 @@ def update_ee_layer_properties(layer, eeObject, visParams, shown, opacity):
# serialize EE code
ee_object = eeObject.serialize()
ee_object_vis = json.dumps(visParams)
layer.setCustomProperty("ee-plugin-version", ee_plugin.ee_plugin.VERSION)
layer.setCustomProperty("ee-plugin-version", ee_plugin_version)
layer.setCustomProperty("ee-object", ee_object)
layer.setCustomProperty("ee-object-vis", ee_object_vis)

Expand All @@ -51,23 +50,7 @@ def add_ee_image_layer(image, name, shown, opacity):
check_version()

url = "type=xyz&url=" + get_ee_image_url(image)

# EE raster data provider
if image.ee_type == ee.Image:
layer = QgsRasterLayer(url, name, "EE")
# EE vector data provider
if image.ee_type in [ee.Geometry, ee.Feature]:
# TODO
layer = QgsRasterLayer(url, name, "wms")
# EE raster collection data provider
if image.ee_type == ee.ImageCollection:
# TODO
layer = QgsRasterLayer(url, name, "wms")
# EE vector collection data provider
if image.ee_type == ee.FeatureCollection:
# TODO
layer = QgsRasterLayer(url, name, "wms")

layer = QgsRasterLayer(url, name, "EE")
QgsProject.instance().addMapLayer(layer)

if shown is not None:
Expand Down
8 changes: 4 additions & 4 deletions pavement.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
options(
plugin=Bunch(
name="ee_plugin",
ext_libs=path("extlibs"),
source_dir=path("."),
ext_libs=path(os.path.join("ee_plugin", "extlibs")),
source_dir=path("ee_plugin"),
package_dir=path("."),
tests=["test", "tests"],
excludes=[
Expand Down Expand Up @@ -76,7 +76,7 @@ def setup():
def install(options):
"""install plugin to qgis"""
plugin_name = options.plugin.name
src = path(__file__).dirname()
src = options.plugin.source_dir
if platform.system() == "Windows":
dst = (
path(
Expand Down Expand Up @@ -149,5 +149,5 @@ def filter_excludes(files):
for root, dirs, files in os.walk(src_dir):
for f in filter_excludes(files):
relpath = os.path.relpath(root, ".")
zipFile.write(path(root) / f, path("ee_plugin") / path(relpath) / f)
zipFile.write(path(root) / f, path(relpath) / f)
filter_excludes(dirs)
3 changes: 0 additions & 3 deletions pytest.ini

This file was deleted.

8 changes: 6 additions & 2 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
-r requirements.txt # Include all main requirements

# Development dependencies
pytest
pytest==7.4.3 # pytest-qgis does not support pytest>=8
pytest-cov
pre-commit
pytest-qgis==2.1.0
pre-commit
pyqt5
future
paver
Binary file renamed .coverage → symbology-style.db
Binary file not shown.
30 changes: 30 additions & 0 deletions test/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import ee
from pytest import fixture
from qgis.utils import plugins
from PyQt5.QtCore import QSettings, QCoreApplication

from ee_plugin.ee_plugin import GoogleEarthEnginePlugin


@fixture(scope="session", autouse=True)
def setup_ee():
"""Initialize the Earth Engine API."""
print("Initializing Earth Engine API...")
ee.Initialize()
ee.Authenticate(auth_mode="localhost", quiet=True)


@fixture(scope="session", autouse=True)
def load_ee_plugin(qgis_app, setup_ee):
"""Load Earth Engine plugin and configure QSettings."""

# Set QSettings values required by the plugin
QCoreApplication.setOrganizationName("QGIS")
QCoreApplication.setApplicationName("QGIS Testing")
QSettings().setValue("locale/userLocale", "en")

# Initialize and register the plugin
plugin = GoogleEarthEnginePlugin(qgis_app)
plugins["ee_plugin"] = plugin
plugin.check_version()
yield qgis_app
7 changes: 6 additions & 1 deletion test/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ def test_read_init(self):
]

file_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.pardir, "metadata.txt")
os.path.join(
os.path.dirname(__file__),
os.pardir,
"ee_plugin",
"metadata.txt",
)
)
LOGGER.info(file_path)
metadata = []
Expand Down
31 changes: 31 additions & 0 deletions test/test_map.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from ee_plugin import Map


def test_add_layer():
"""Test adding a layer to the map."""
import ee

image = ee.Image("USGS/SRTMGL1_003")
vis_params = {
"min": 0,
"max": 4000,
"palette": ["006633", "E5FFCC", "662A00", "D8D8D8", "F5F5F5"],
}

# Add the layer to the map
Map.addLayer(image, vis_params, "DEM")


def test_get_bounds():
"""Test getting the bounds of the map."""
bounds = Map.getBounds()
assert len(bounds) == 4, "Bounds do not have the expected format."
assert all(
isinstance(coord, (float, int)) for coord in bounds
), "Bounds coordinates are not numeric."


def test_get_scale():
"""Test getting the map scale."""
scale = Map.getScale()
assert scale > 0, "Scale should be a positive number."
1 change: 1 addition & 0 deletions test/test_qgis_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def test_qgis_environment(self):
r = QgsProviderRegistry.instance()
self.assertIn("gdal", r.providerList())
self.assertIn("ogr", r.providerList())
self.assertIn("wms", r.providerList()) # needed for our EE provider

def test_projection(self):
"""Test that QGIS properly parses a wkt string."""
Expand Down
6 changes: 3 additions & 3 deletions test/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ class GoogleEarthEngineResourcesTest(unittest.TestCase):
def test_icon_png(self):
"""Test image paths exist"""
paths = (
"icons/google-cloud-project.svg",
"icons/google-cloud.svg",
"./icons/earth-engine.svg",
"ee_plugin/icons/google-cloud-project.svg",
"ee_plugin/icons/google-cloud.svg",
"ee_plugin/icons/earth-engine.svg",
)
for path in paths:
icon = QIcon(path)
Expand Down
2 changes: 1 addition & 1 deletion test/test_translations.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test_qgis_translations(self):
"""Test that translations work."""
parent_path = os.path.join(__file__, os.path.pardir, os.path.pardir)
dir_path = os.path.abspath(parent_path)
file_path = os.path.join(dir_path, "i18n", "af.qm")
file_path = os.path.join(dir_path, "ee_plugin", "i18n", "af.qm")
translator = QTranslator()
translator.load(file_path)
QCoreApplication.installTranslator(translator)
Expand Down
44 changes: 44 additions & 0 deletions test/test_vector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import ee
import pytest

from ee_plugin import Map

# initialize the Earth Engine API is required to use the ee.Geometry module
# and runs before fixtures
ee.Initialize()

geometries = [
(ee.Geometry.Point([1.5, 1.5]), {"color": "1eff05"}, "point"),
(
ee.Geometry.LineString([[-35, -10], [35, -10], [35, 10], [-35, 10]]),
{"color": "FF0000"},
"lineString",
),
(
ee.Geometry.LinearRing(
[[-35, -10], [35, -10], [35, 10], [-35, 10], [-35, -10]]
),
{"color": "ee38ff"},
"linearRing",
),
(ee.Geometry.Rectangle([-40, -20, 40, 20]), {"color": "ffa05c"}, "rectangle"),
(
ee.Geometry.Polygon([[[-5, 40], [65, 40], [65, 60], [-5, 60], [-5, 40]]]),
{"color": "FF0000"},
"geodesic polygon",
),
(
ee.Geometry(
ee.Geometry.Polygon([[[-5, 40], [65, 40], [65, 60], [-5, 60], [-5, 40]]]),
None,
False,
),
{"color": "000000"},
"planar polygon",
),
]


@pytest.mark.parametrize("geometry, vis_params, layer_name", geometries)
def test_add_geometry_layer(geometry, vis_params, layer_name):
Map.addLayer(geometry, vis_params, layer_name), "Layer added successfully"
Loading