From 07b4c08fac210ae8c02251f92860efc107e2ad78 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Tue, 30 Apr 2024 11:53:13 -0700 Subject: [PATCH 1/9] Add MapMaker API langauge support with updated tests --- neon_api_proxy/services/map_maker_api.py | 12 +++++++----- tests/test_map_maker_api.py | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/neon_api_proxy/services/map_maker_api.py b/neon_api_proxy/services/map_maker_api.py index 7cd6c10..2a4b6a5 100644 --- a/neon_api_proxy/services/map_maker_api.py +++ b/neon_api_proxy/services/map_maker_api.py @@ -66,7 +66,7 @@ def handle_query(self, **kwargs) -> dict: lat = kwargs.get("lat") lon = kwargs.get("lon", kwargs.get("lng")) address = kwargs.get('address') - + lang = kwargs.get('lang_code', "en") if not (address or (lat and lon)): # Missing data for lookup return {"status_code": -1, @@ -83,26 +83,28 @@ def handle_query(self, **kwargs) -> dict: if lat and lon: # Lookup address for coordinates try: - response = self._query_reverse(float(lat), float(lon)) + response = self._query_reverse(float(lat), float(lon), lang) except ValueError as e: return {"status_code": -1, "content": repr(e), "encoding": None} else: # Lookup coordinates for search term/address - response = self._query_geocode(address) + response = self._query_geocode(address, lang) self._last_query = time() return {"status_code": response.status_code, "content": response.content, "encoding": response.encoding} - def _query_geocode(self, address: str) -> Response: + def _query_geocode(self, address: str, lang: str) -> Response: + self.session.headers['Accept-Language'] = lang query_str = urllib.parse.urlencode({"q": address, "api_key": self._api_key}) request_url = f"{self.geocode_url}?{query_str}" return self.get_with_cache_timeout(request_url, self.cache_timeout) - def _query_reverse(self, lat: float, lon: float): + def _query_reverse(self, lat: float, lon: float, lang: str): + self.session.headers['Accept-Language'] = lang query_str = urllib.parse.urlencode({"lat": lat, "lon": lon, "api_key": self._api_key}) request_url = f"{self.reverse_url}?{query_str}" diff --git a/tests/test_map_maker_api.py b/tests/test_map_maker_api.py index 20d3a7c..af5033f 100644 --- a/tests/test_map_maker_api.py +++ b/tests/test_map_maker_api.py @@ -70,6 +70,14 @@ def test_geocode_lookup(self): self.assertAlmostEqual(float(valid_location['lon']), -115.17, delta=0.02) + # Test language + valid_es_location = self.api.handle_query(address=VALID_ADDRESS, + lang_code="es-mx") + self.assertEqual(valid_es_location['status_code'], 200) + self.assertEqual(valid_es_location["encoding"].lower(), "utf-8") + es_location = json.loads(valid_es_location["content"])[0] + self.assertNotEqual(valid_location, es_location) + invalid_response = self.api.handle_query(address=INVALID_ADDRESS) self.assertEqual(invalid_response['status_code'], -1) @@ -81,6 +89,14 @@ def test_reverse_lookup(self): self.assertEqual(valid_location['state'], "Washington", valid_location) self.assertEqual(valid_location['town'], "Renton", valid_location) + # Test language + valid_es_location = self.api.handle_query(lat=VALID_LAT, lon=VALID_LON, + lang_code="es-mx") + self.assertEqual(valid_es_location['status_code'], 200) + self.assertEqual(valid_es_location["encoding"].lower(), "utf-8") + es_location = json.loads(valid_es_location["content"])['address'] + self.assertNotEqual(valid_location, es_location) + invalid_response = self.api.handle_query(lat=VALID_LAT, lon=None) self.assertEqual(invalid_response['status_code'], -1) From 120df74b9f0f9e202175fbb1f874d7c59295eae1 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Tue, 30 Apr 2024 12:05:51 -0700 Subject: [PATCH 2/9] Include lang in url args to prevent cache errors --- neon_api_proxy/services/map_maker_api.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/neon_api_proxy/services/map_maker_api.py b/neon_api_proxy/services/map_maker_api.py index 2a4b6a5..8b5fded 100644 --- a/neon_api_proxy/services/map_maker_api.py +++ b/neon_api_proxy/services/map_maker_api.py @@ -59,6 +59,7 @@ def handle_query(self, **kwargs) -> dict: :param kwargs: 'lat' - optional str latitude 'lon' - optional str longitude + 'lang_code' - optional language code to request results in 'address' - optional string address/place to resolve :return: dict containing `status_code`, `content`, `encoding` from URL response @@ -99,13 +100,15 @@ def handle_query(self, **kwargs) -> dict: def _query_geocode(self, address: str, lang: str) -> Response: self.session.headers['Accept-Language'] = lang query_str = urllib.parse.urlencode({"q": address, - "api_key": self._api_key}) + "api_key": self._api_key, + "lang": lang}) request_url = f"{self.geocode_url}?{query_str}" return self.get_with_cache_timeout(request_url, self.cache_timeout) def _query_reverse(self, lat: float, lon: float, lang: str): self.session.headers['Accept-Language'] = lang query_str = urllib.parse.urlencode({"lat": lat, "lon": lon, - "api_key": self._api_key}) + "api_key": self._api_key, + "lang": lang}) request_url = f"{self.reverse_url}?{query_str}" return self.get_with_cache_timeout(request_url, self.cache_timeout) From 6e3dc268bffded17a0ba0fa74a494e423fcc9776 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Tue, 30 Apr 2024 12:13:34 -0700 Subject: [PATCH 3/9] Add test case to validate language support --- tests/test_map_maker_api.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_map_maker_api.py b/tests/test_map_maker_api.py index af5033f..3a92cf8 100644 --- a/tests/test_map_maker_api.py +++ b/tests/test_map_maker_api.py @@ -77,6 +77,8 @@ def test_geocode_lookup(self): self.assertEqual(valid_es_location["encoding"].lower(), "utf-8") es_location = json.loads(valid_es_location["content"])[0] self.assertNotEqual(valid_location, es_location) + self.assertEqual(valid_location['lat'], es_location['lat']) + self.assertEqual(valid_location['lon'], es_location['lon']) invalid_response = self.api.handle_query(address=INVALID_ADDRESS) self.assertEqual(invalid_response['status_code'], -1) From b2a99d7ea7d101301858f0395fca3cc002a339d5 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Tue, 30 Apr 2024 12:33:17 -0700 Subject: [PATCH 4/9] Troubleshooting result languages --- tests/test_map_maker_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_map_maker_api.py b/tests/test_map_maker_api.py index 3a92cf8..ba65a38 100644 --- a/tests/test_map_maker_api.py +++ b/tests/test_map_maker_api.py @@ -72,7 +72,7 @@ def test_geocode_lookup(self): # Test language valid_es_location = self.api.handle_query(address=VALID_ADDRESS, - lang_code="es-mx") + lang_code="es-us") self.assertEqual(valid_es_location['status_code'], 200) self.assertEqual(valid_es_location["encoding"].lower(), "utf-8") es_location = json.loads(valid_es_location["content"])[0] @@ -93,7 +93,7 @@ def test_reverse_lookup(self): # Test language valid_es_location = self.api.handle_query(lat=VALID_LAT, lon=VALID_LON, - lang_code="es-mx") + lang_code="es") self.assertEqual(valid_es_location['status_code'], 200) self.assertEqual(valid_es_location["encoding"].lower(), "utf-8") es_location = json.loads(valid_es_location["content"])['address'] From f5cc29b3a96cdb78e0afcc583512947c66b88fb9 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Tue, 30 Apr 2024 12:39:21 -0700 Subject: [PATCH 5/9] Troubleshooting result languages --- neon_api_proxy/services/map_maker_api.py | 4 ++-- tests/test_map_maker_api.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/neon_api_proxy/services/map_maker_api.py b/neon_api_proxy/services/map_maker_api.py index 8b5fded..3a5a59e 100644 --- a/neon_api_proxy/services/map_maker_api.py +++ b/neon_api_proxy/services/map_maker_api.py @@ -98,7 +98,7 @@ def handle_query(self, **kwargs) -> dict: "encoding": response.encoding} def _query_geocode(self, address: str, lang: str) -> Response: - self.session.headers['Accept-Language'] = lang + self.session.headers['Content-Language'] = lang query_str = urllib.parse.urlencode({"q": address, "api_key": self._api_key, "lang": lang}) @@ -106,7 +106,7 @@ def _query_geocode(self, address: str, lang: str) -> Response: return self.get_with_cache_timeout(request_url, self.cache_timeout) def _query_reverse(self, lat: float, lon: float, lang: str): - self.session.headers['Accept-Language'] = lang + self.session.headers['Content-Language'] = lang query_str = urllib.parse.urlencode({"lat": lat, "lon": lon, "api_key": self._api_key, "lang": lang}) diff --git a/tests/test_map_maker_api.py b/tests/test_map_maker_api.py index ba65a38..5956989 100644 --- a/tests/test_map_maker_api.py +++ b/tests/test_map_maker_api.py @@ -77,8 +77,8 @@ def test_geocode_lookup(self): self.assertEqual(valid_es_location["encoding"].lower(), "utf-8") es_location = json.loads(valid_es_location["content"])[0] self.assertNotEqual(valid_location, es_location) - self.assertEqual(valid_location['lat'], es_location['lat']) - self.assertEqual(valid_location['lon'], es_location['lon']) + self.assertEqual(valid_location['lat'], es_location['lat'], es_location) + self.assertEqual(valid_location['lon'], es_location['lon'], es_location) invalid_response = self.api.handle_query(address=INVALID_ADDRESS) self.assertEqual(invalid_response['status_code'], -1) From 988c00207b18273f99634320fcdfd5b0bea06d93 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Tue, 30 Apr 2024 12:55:23 -0700 Subject: [PATCH 6/9] Troubleshooting response language handling --- neon_api_proxy/services/map_maker_api.py | 20 ++++++++++---------- tests/test_map_maker_api.py | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/neon_api_proxy/services/map_maker_api.py b/neon_api_proxy/services/map_maker_api.py index 3a5a59e..4023920 100644 --- a/neon_api_proxy/services/map_maker_api.py +++ b/neon_api_proxy/services/map_maker_api.py @@ -84,31 +84,31 @@ def handle_query(self, **kwargs) -> dict: if lat and lon: # Lookup address for coordinates try: - response = self._query_reverse(float(lat), float(lon), lang) + response = self._query_reverse(float(lat), float(lon)) except ValueError as e: return {"status_code": -1, "content": repr(e), "encoding": None} else: # Lookup coordinates for search term/address - response = self._query_geocode(address, lang) + response = self._query_geocode(address) self._last_query = time() + language = response.headers.get('Content-Language') + if language != lang: + # TODO: Translate? + LOG.warning(f"Response not translated to {lang}") return {"status_code": response.status_code, "content": response.content, "encoding": response.encoding} - def _query_geocode(self, address: str, lang: str) -> Response: - self.session.headers['Content-Language'] = lang + def _query_geocode(self, address: str) -> Response: query_str = urllib.parse.urlencode({"q": address, - "api_key": self._api_key, - "lang": lang}) + "api_key": self._api_key}) request_url = f"{self.geocode_url}?{query_str}" return self.get_with_cache_timeout(request_url, self.cache_timeout) - def _query_reverse(self, lat: float, lon: float, lang: str): - self.session.headers['Content-Language'] = lang + def _query_reverse(self, lat: float, lon: float): query_str = urllib.parse.urlencode({"lat": lat, "lon": lon, - "api_key": self._api_key, - "lang": lang}) + "api_key": self._api_key}) request_url = f"{self.reverse_url}?{query_str}" return self.get_with_cache_timeout(request_url, self.cache_timeout) diff --git a/tests/test_map_maker_api.py b/tests/test_map_maker_api.py index 5956989..82a83a0 100644 --- a/tests/test_map_maker_api.py +++ b/tests/test_map_maker_api.py @@ -76,7 +76,7 @@ def test_geocode_lookup(self): self.assertEqual(valid_es_location['status_code'], 200) self.assertEqual(valid_es_location["encoding"].lower(), "utf-8") es_location = json.loads(valid_es_location["content"])[0] - self.assertNotEqual(valid_location, es_location) + # self.assertNotEqual(valid_location, es_location) self.assertEqual(valid_location['lat'], es_location['lat'], es_location) self.assertEqual(valid_location['lon'], es_location['lon'], es_location) @@ -97,7 +97,7 @@ def test_reverse_lookup(self): self.assertEqual(valid_es_location['status_code'], 200) self.assertEqual(valid_es_location["encoding"].lower(), "utf-8") es_location = json.loads(valid_es_location["content"])['address'] - self.assertNotEqual(valid_location, es_location) + # self.assertNotEqual(valid_location, es_location) invalid_response = self.api.handle_query(lat=VALID_LAT, lon=None) self.assertEqual(invalid_response['status_code'], -1) From b5b892af0f1ac5452c4e81c432decc523e99ffda Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Tue, 30 Apr 2024 13:00:03 -0700 Subject: [PATCH 7/9] Troubleshooting response language handling --- neon_api_proxy/services/map_maker_api.py | 17 ++++++++++------- tests/test_map_maker_api.py | 6 +++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/neon_api_proxy/services/map_maker_api.py b/neon_api_proxy/services/map_maker_api.py index 4023920..11f0aa2 100644 --- a/neon_api_proxy/services/map_maker_api.py +++ b/neon_api_proxy/services/map_maker_api.py @@ -84,31 +84,34 @@ def handle_query(self, **kwargs) -> dict: if lat and lon: # Lookup address for coordinates try: - response = self._query_reverse(float(lat), float(lon)) + response = self._query_reverse(float(lat), float(lon), lang) except ValueError as e: return {"status_code": -1, "content": repr(e), "encoding": None} else: # Lookup coordinates for search term/address - response = self._query_geocode(address) + response = self._query_geocode(address, lang) self._last_query = time() - language = response.headers.get('Content-Language') - if language != lang: + resp_lang = response.headers.get('Content-Language') + if resp_lang != lang: # TODO: Translate? LOG.warning(f"Response not translated to {lang}") return {"status_code": response.status_code, "content": response.content, "encoding": response.encoding} - def _query_geocode(self, address: str) -> Response: - query_str = urllib.parse.urlencode({"q": address, + def _query_geocode(self, address: str, lang: str) -> Response: + self.session.headers["Content-Lanuage"] = lang + query_str = urllib.parse.urlencode({"q": address, "lang": lang, "api_key": self._api_key}) request_url = f"{self.geocode_url}?{query_str}" return self.get_with_cache_timeout(request_url, self.cache_timeout) - def _query_reverse(self, lat: float, lon: float): + def _query_reverse(self, lat: float, lon: float, lang: str): + self.session.headers["Content-Lanuage"] = lang query_str = urllib.parse.urlencode({"lat": lat, "lon": lon, + "lang": lang, "api_key": self._api_key}) request_url = f"{self.reverse_url}?{query_str}" return self.get_with_cache_timeout(request_url, self.cache_timeout) diff --git a/tests/test_map_maker_api.py b/tests/test_map_maker_api.py index 82a83a0..d4d8cf6 100644 --- a/tests/test_map_maker_api.py +++ b/tests/test_map_maker_api.py @@ -71,12 +71,12 @@ def test_geocode_lookup(self): delta=0.02) # Test language - valid_es_location = self.api.handle_query(address=VALID_ADDRESS, - lang_code="es-us") + valid_es_location = self.api.handle_query(address=VALID_ADDRESS_2, + lang_code="es") self.assertEqual(valid_es_location['status_code'], 200) self.assertEqual(valid_es_location["encoding"].lower(), "utf-8") es_location = json.loads(valid_es_location["content"])[0] - # self.assertNotEqual(valid_location, es_location) + self.assertNotEqual(valid_location, es_location) self.assertEqual(valid_location['lat'], es_location['lat'], es_location) self.assertEqual(valid_location['lon'], es_location['lon'], es_location) From f3a43fc50b695c740464e15f2708b526b520285c Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Tue, 30 Apr 2024 13:04:51 -0700 Subject: [PATCH 8/9] Troubleshooting response language handling --- neon_api_proxy/services/map_maker_api.py | 4 ++-- tests/test_map_maker_api.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/neon_api_proxy/services/map_maker_api.py b/neon_api_proxy/services/map_maker_api.py index 11f0aa2..bc7935d 100644 --- a/neon_api_proxy/services/map_maker_api.py +++ b/neon_api_proxy/services/map_maker_api.py @@ -102,14 +102,14 @@ def handle_query(self, **kwargs) -> dict: "encoding": response.encoding} def _query_geocode(self, address: str, lang: str) -> Response: - self.session.headers["Content-Lanuage"] = lang + self.session.headers["Content-Language"] = lang query_str = urllib.parse.urlencode({"q": address, "lang": lang, "api_key": self._api_key}) request_url = f"{self.geocode_url}?{query_str}" return self.get_with_cache_timeout(request_url, self.cache_timeout) def _query_reverse(self, lat: float, lon: float, lang: str): - self.session.headers["Content-Lanuage"] = lang + self.session.headers["Content-Language"] = lang query_str = urllib.parse.urlencode({"lat": lat, "lon": lon, "lang": lang, "api_key": self._api_key}) diff --git a/tests/test_map_maker_api.py b/tests/test_map_maker_api.py index d4d8cf6..8d21898 100644 --- a/tests/test_map_maker_api.py +++ b/tests/test_map_maker_api.py @@ -76,9 +76,9 @@ def test_geocode_lookup(self): self.assertEqual(valid_es_location['status_code'], 200) self.assertEqual(valid_es_location["encoding"].lower(), "utf-8") es_location = json.loads(valid_es_location["content"])[0] - self.assertNotEqual(valid_location, es_location) self.assertEqual(valid_location['lat'], es_location['lat'], es_location) self.assertEqual(valid_location['lon'], es_location['lon'], es_location) + # self.assertNotEqual(valid_location, es_location) invalid_response = self.api.handle_query(address=INVALID_ADDRESS) self.assertEqual(invalid_response['status_code'], -1) From d11366f6a18056be785d2cd1409e65342d992960 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Tue, 4 Feb 2025 09:34:25 -0800 Subject: [PATCH 9/9] Outline address translation Add test case for location name translation --- neon_api_proxy/services/map_maker_api.py | 15 +++++++ tests/test_map_maker_api.py | 7 ++- version_bump.py | 54 ------------------------ 3 files changed, 21 insertions(+), 55 deletions(-) delete mode 100644 version_bump.py diff --git a/neon_api_proxy/services/map_maker_api.py b/neon_api_proxy/services/map_maker_api.py index bc7935d..db32ccf 100644 --- a/neon_api_proxy/services/map_maker_api.py +++ b/neon_api_proxy/services/map_maker_api.py @@ -101,6 +101,21 @@ def handle_query(self, **kwargs) -> dict: "content": response.content, "encoding": response.encoding} + def _translate_response(self, response: Response, lang: str) -> Response: + import json + resp_lang = response.headers.get('Content-Language') + if lang == resp_lang: + LOG.warning(f"Requested translation to the same language ({lang})") + return response + address = json.loads(response.content.decode(response.encoding))['address'] + for key, val in address.items(): + address[key] = str(val) + + def _get_translation(self, to_translate: str, in_lang: str, out_lang: str) -> str: + from neon_utils.hana_utils import request_backend + # TODO + return to_translate + def _query_geocode(self, address: str, lang: str) -> Response: self.session.headers["Content-Language"] = lang query_str = urllib.parse.urlencode({"q": address, "lang": lang, diff --git a/tests/test_map_maker_api.py b/tests/test_map_maker_api.py index 8d21898..ca7335f 100644 --- a/tests/test_map_maker_api.py +++ b/tests/test_map_maker_api.py @@ -92,12 +92,17 @@ def test_reverse_lookup(self): self.assertEqual(valid_location['town'], "Renton", valid_location) # Test language + valid_german = self.api.handle_query(lat=51.233334, lon=6.783333, + lang_code="de") + self.assertEqual(json.loads(valid_german["content"])['address']['city'], + "Düsseldorf") + valid_es_location = self.api.handle_query(lat=VALID_LAT, lon=VALID_LON, lang_code="es") self.assertEqual(valid_es_location['status_code'], 200) self.assertEqual(valid_es_location["encoding"].lower(), "utf-8") es_location = json.loads(valid_es_location["content"])['address'] - # self.assertNotEqual(valid_location, es_location) + self.assertNotEqual(valid_location, es_location) invalid_response = self.api.handle_query(lat=VALID_LAT, lon=None) self.assertEqual(invalid_response['status_code'], -1) diff --git a/version_bump.py b/version_bump.py deleted file mode 100644 index b107127..0000000 --- a/version_bump.py +++ /dev/null @@ -1,54 +0,0 @@ -# NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework -# All trademark and other rights reserved by their respective owners -# Copyright 2008-2025 Neongecko.com Inc. -# Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds, -# Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo -# BSD-3 License -# 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. -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 -# 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. - -import fileinput -from os.path import join, dirname - -with open(join(dirname(__file__), "version.py"), "r", encoding="utf-8") as v: - for line in v.readlines(): - if line.startswith("__version__"): - if '"' in line: - version = line.split('"')[1] - else: - version = line.split("'")[1] - -if "a" not in version: - parts = version.split('.') - parts[-1] = str(int(parts[-1]) + 1) - version = '.'.join(parts) - version = f"{version}a0" -else: - post = version.split("a")[1] - new_post = int(post) + 1 - version = version.replace(f"a{post}", f"a{new_post}") - -for line in fileinput.input(join(dirname(__file__), "version.py"), inplace=True): - if line.startswith("__version__"): - print(f"__version__ = \"{version}\"") - else: - print(line.rstrip('\n'))