-
Notifications
You must be signed in to change notification settings - Fork 1
[IMP] 19.0.local messy #6
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,22 +2,27 @@ | |
| # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
| import logging | ||
|
|
||
| from shapely.errors import GEOSException | ||
|
|
||
| from odoo import _ | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
| _logger = logging.getLogger(__name__) | ||
|
|
||
| try: | ||
| import geojson | ||
| from shapely import wkb, wkt | ||
| from shapely.geometry import shape | ||
| from shapely.geometry.base import BaseGeometry | ||
| except ImportError: | ||
| logger = logging.getLogger(__name__) | ||
| logger.warning(_("Shapely or geojson are not available in the sys path")) # pylint: disable=prefer-env-translation | ||
| _logger.warning(_("Shapely or geojson are not available in the sys path")) # pylint: disable=prefer-env-translation | ||
|
|
||
|
|
||
| def value_to_shape(value, use_wkb=False): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue (complexity): Consider simplifying You can keep the new behavior while reducing complexity and making the flow easier to reason about. 1. Make
|
||
| """Transforms input into a Shapely object""" | ||
|
|
||
| # always use_wkb for now | ||
| use_wkb = True | ||
|
Comment on lines
+23
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: Overriding Forcing |
||
|
|
||
| if not value: | ||
| return wkt.loads("GEOMETRYCOLLECTION EMPTY") | ||
| if isinstance(value, str): | ||
|
|
@@ -26,19 +31,35 @@ def value_to_shape(value, use_wkb=False): | |
| if "{" in value: | ||
| geo_dict = geojson.loads(value) | ||
| return shape(geo_dict) | ||
| elif use_wkb: | ||
| return wkb.loads(value, hex=True) | ||
| else: | ||
| # <NIKMOD> | ||
| # 'POINT(0.0 0.0)' | ||
|
|
||
| if use_wkb: | ||
| try: | ||
| return wkt.loads(value) | ||
| res = wkb.loads(value, hex=True) | ||
| return res | ||
| except GEOSException as e: | ||
| _logger.warning("GEOSException:") | ||
| _logger.warning(e) | ||
|
Comment on lines
+38
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: Exception logging for GEOS/WKB failures could include more context to aid debugging. Right now the GEOSException handler logs only a label and the exception. Please log some minimal context about the input (e.g. type and/or length) and pass _logger.warning(
"GEOSException while loading WKB (len=%s)",
len(value),
exc_info=True,
)The same improvement would help in the generic WKB conversion failure case as well. |
||
| except Exception as e: | ||
| logger.warning(_("Failed to parse WKT: %s", e)) # pylint: disable=prefer-env-translation | ||
| empty = "POINT(0.0 0.0)" | ||
| return wkt.loads(empty) | ||
| # </NIKMOD> | ||
| _logger.warning("WKB conversion failed:") | ||
| _logger.warning(e) | ||
| # elif len(value) == 42 and "POINT" not in value and "(" not in value: | ||
| # not clear why use_wkb is not set correctly anymore. | ||
| # if a record is stored it's instantly | ||
| # executed again with the hash value | ||
| # The hash value eg "0101000000A4703D0AD7232C400AD7A3703D0A4840" | ||
| # is also possible, but we do not handle it now. | ||
| # value = wkb.loads(value, hex=True) | ||
| # return value | ||
| # <NIKMOD> | ||
| # 'POINT(0.0 0.0)' | ||
| try: | ||
| return wkt.loads(value) | ||
| except Exception as e: | ||
| # error = _("Failed to parse WKT: %(e)s") % {"e":e} | ||
| error = f"Failed to parse WKT: {e}" | ||
| _logger.warning(error) # pylint: disable=prefer-env-translation | ||
| empty = "POINT(0 0)" | ||
| return wkt.loads(empty) | ||
| # </NIKMOD> | ||
| elif hasattr(value, "wkt"): | ||
| return value if isinstance(value, BaseGeometry) else wkt.loads(value.wkt) | ||
| else: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,5 @@ The module also requires two additional python libs: | |
|
|
||
| When you will install the module this two additional libs will be | ||
| installed. | ||
|
|
||
| For a complete documentation please refer to the [public | ||
| documenation](http://oca.github.io/geospatial/index.html) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue (typo): Correct the typo "documenation" and consider adjusting "a complete documentation". This nearby line has the same typo: "documenation" → "documentation". Also consider changing "a complete documentation" to "the complete documentation" or simply "complete documentation" for better grammar. |
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -430,8 +430,7 @@ <h2><a class="toc-backref" href="#toc-entry-1">Installation</a></h2> | |||||
| <li><a class="reference external" href="http://pypi.python.org/pypi/geojson">geojson</a></li> | ||||||
| </ul> | ||||||
| <p>When you will install the module this two additional libs will be | ||||||
| installed.</p> | ||||||
| <p>For a complete documentation please refer to the <a class="reference external" href="http://oca.github.io/geospatial/index.html">public | ||||||
| installed. For a complete documentation please refer to the <a class="reference external" href="http://oca.github.io/geospatial/index.html">public | ||||||
| documenation</a></p> | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick (typo): Minor spelling issue in the updated sentence. The link text currently says
Suggested change
|
||||||
| </div> | ||||||
| <div class="section" id="usage"> | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,12 @@ | ||
| # Copyright 2023 ACSONE SA/NV | ||
|
|
||
| import geojson | ||
| from odoo_test_helper import FakeModelLoader | ||
|
|
||
| # from odoo_test_helper import FakeModelLoader | ||
| from shapely import wkt | ||
| from shapely.geometry import shape | ||
|
|
||
| from odoo.orm.model_classes import add_to_registry | ||
| from odoo.tests.common import TransactionCase | ||
|
|
||
| from ..fields import GeoPoint | ||
|
|
@@ -14,12 +16,25 @@ class TestModel(TransactionCase): | |
| @classmethod | ||
| def setUpClass(cls): | ||
| super().setUpClass() | ||
| cls.loader = FakeModelLoader(cls.env, cls.__module__) | ||
| cls.loader.backup_registry() | ||
|
|
||
| from .models import DummyZip, GeoModelTest, RetailMachine | ||
|
|
||
| cls.loader.update_registry((GeoModelTest, DummyZip, RetailMachine)) | ||
| add_to_registry(cls.registry, GeoModelTest) | ||
| cls.registry._setup_models__(cls.env.cr, ["geo.model.test"]) | ||
| cls.registry.init_models( | ||
| cls.env.cr, ["geo.model.test"], {"models_to_check": True} | ||
| ) | ||
|
|
||
| add_to_registry(cls.registry, DummyZip) | ||
| cls.registry._setup_models__(cls.env.cr, ["dummy.zip"]) | ||
| cls.registry.init_models(cls.env.cr, ["dummy.zip"], {"models_to_check": True}) | ||
|
|
||
| add_to_registry(cls.registry, RetailMachine) | ||
| cls.registry._setup_models__(cls.env.cr, ["retail.machine"]) | ||
| cls.registry.init_models( | ||
| cls.env.cr, ["retail.machine"], {"models_to_check": True} | ||
| ) | ||
|
|
||
| cls.geo_model = cls.env["geo.model.test"].create({}) | ||
| cls.env["dummy.zip"].create( | ||
| { | ||
|
|
@@ -145,7 +160,10 @@ def setUpClass(cls): | |
|
|
||
| @classmethod | ||
| def tearDownClass(cls): | ||
| cls.loader.restore_registry() | ||
| cls.addClassCleanup(cls.registry.__delitem__, "geo.model.test") | ||
| cls.addClassCleanup(cls.registry.__delitem__, "retail.machine") | ||
| cls.addClassCleanup(cls.registry.__delitem__, "dummy.zip") | ||
|
|
||
| super().tearDownClass() | ||
|
|
||
| def test_create_multipolygon_wkt_format(self): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (testing): Add tests covering invalid WKB/WKT inputs to reflect the new fallback behavior in value_to_shape These changes add new behavior in Suggested implementation: def test_create_multipolygon_wkt_format(self):
GeoModel = self.env["geo.model.test"]
wkt_multipolygon = "MULTIPOLYGON(((0 0,0 1,1 1,0 0)))"
rec = GeoModel.create(
{
"name": "wkt-multipolygon",
"the_geom": wkt_multipolygon,
}
)
# Ensure a valid geometry is created and it is a multipolygon
self.assertTrue(rec.the_geom)
self.assertEqual(rec.the_geom.geom_type, "MultiPolygon")
def test_invalid_wkb_and_wkt_fallback_to_default_point(self):
GeoModel = self.env["geo.model.test"]
# This is an invalid hex WKB string and also not a valid WKT
invalid_wkb_and_wkt = "DEADBEEF"
rec = GeoModel.create(
{
"name": "invalid-wkb-wkt",
"the_geom": invalid_wkb_and_wkt,
}
)
# value_to_shape should catch GEOSException / parse errors and
# fall back to the default POINT(0 0) geometry
self.assertTrue(rec.the_geom)
self.assertEqual(rec.the_geom.geom_type, "Point")
self.assertEqual(getattr(rec.the_geom, "x", None), 0)
self.assertEqual(getattr(rec.the_geom, "y", None), 0)
def test_non_geo_string_falls_back_to_default_point(self):
GeoModel = self.env["geo.model.test"]
non_geo_value = "this-is-not-a-geometry"
rec = GeoModel.create(
{
"name": "non-geo-string",
"the_geom": non_geo_value,
}
)
# Both WKB and WKT parsing should fail and we should still get
# the default POINT(0 0) geometry
self.assertTrue(rec.the_geom)
self.assertEqual(rec.the_geom.geom_type, "Point")
self.assertEqual(getattr(rec.the_geom, "x", None), 0)
self.assertEqual(getattr(rec.the_geom, "y", None), 0)
def test_valid_wkt_with_wkb_first_parsing(self):
GeoModel = self.env["geo.model.test"]
# Valid WKT that should still be correctly parsed even though
# value_to_shape now tries WKB parsing first
wkt_point = "POINT(1 2)"
rec = GeoModel.create(
{
"name": "valid-wkt-point",
"the_geom": wkt_point,
}
)
self.assertTrue(rec.the_geom)
self.assertEqual(rec.the_geom.geom_type, "Point")
self.assertEqual(getattr(rec.the_geom, "x", None), 1)
self.assertEqual(getattr(rec.the_geom, "y", None), 2)
def test_search_within_for_retails_34(self):
|
||
|
|
@@ -481,7 +499,7 @@ def test_search_contains_for_retails_21(self): | |
|
|
||
| def test_search_within_for_retails_34(self): | ||
| retails = self.env["retail.machine"] | ||
| zip_item = self.env["dummy.zip"].search([("city", "ilike", "Yens")]) | ||
| zip_item = self.env["dummy.zip"].search([("city", "=", "Yens")], limit=1) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (testing): Strengthen the test by asserting the setup data (zip_item) is found before using it With the stricter domain, if |
||
| result = retails.search( | ||
| [("name", "ilike", "34"), ("the_point", "geo_within", zip_item.the_geom)] | ||
| ) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (typo): Fix typo "documenation" and consider improving the article before "complete documentation".
'documentation' is misspelled, and "the complete documentation" or just "complete documentation" would be more natural here.