From 1f0796778754d8df0dfab9dd01302e26a397f064 Mon Sep 17 00:00:00 2001
From: Sarah Hoffmann
Date: Sun, 10 Nov 2024 22:47:14 +0100
Subject: [PATCH 1/1] fix style issue found by flake8
---
.pylintrc | 22 ----
src/nominatim_api/config.py | 2 +-
src/nominatim_api/connection.py | 15 +--
src/nominatim_api/core.py | 50 ++------
src/nominatim_api/errors.py | 1 +
src/nominatim_api/localization.py | 6 +-
src/nominatim_api/logging.py | 44 ++-----
src/nominatim_api/lookup.py | 3 +-
src/nominatim_api/result_formatting.py | 10 +-
src/nominatim_api/results.py | 51 ++++----
src/nominatim_api/reverse.py | 115 +++++++----------
src/nominatim_api/search/db_search_builder.py | 43 ++-----
src/nominatim_api/search/db_search_fields.py | 9 --
src/nominatim_api/search/db_search_lookups.py | 26 ++--
src/nominatim_api/search/db_searches.py | 89 ++++++-------
src/nominatim_api/search/geocoder.py | 23 ++--
src/nominatim_api/search/icu_tokenizer.py | 16 +--
src/nominatim_api/search/query.py | 22 +---
.../search/query_analyzer_factory.py | 3 +-
src/nominatim_api/search/token_assignment.py | 33 ++---
src/nominatim_api/server/asgi_adaptor.py | 11 +-
src/nominatim_api/server/falcon/server.py | 21 ++--
src/nominatim_api/server/starlette/server.py | 12 +-
src/nominatim_api/sql/async_core_library.py | 4 +-
src/nominatim_api/sql/sqlalchemy_functions.py | 36 +++---
src/nominatim_api/sql/sqlalchemy_schema.py | 32 +++--
.../sql/sqlalchemy_types/geometry.py | 59 +++------
.../sql/sqlalchemy_types/int_array.py | 13 +-
.../sql/sqlalchemy_types/json.py | 3 +-
.../sql/sqlalchemy_types/key_value.py | 17 ++-
src/nominatim_api/sql/sqlite_functions.py | 3 +-
src/nominatim_api/status.py | 1 +
src/nominatim_api/types.py | 59 ++++-----
src/nominatim_api/typing.py | 2 +-
src/nominatim_api/utils/json_writer.py | 16 +--
src/nominatim_api/v1/__init__.py | 2 -
src/nominatim_api/v1/classtypes.py | 5 +-
src/nominatim_api/v1/format.py | 71 ++++++-----
src/nominatim_api/v1/format_json.py | 63 +++++-----
src/nominatim_api/v1/format_xml.py | 5 +-
src/nominatim_api/v1/helpers.py | 11 +-
src/nominatim_api/v1/server_glue.py | 36 +++---
src/nominatim_db/cli.py | 14 +--
src/nominatim_db/clicmd/add_data.py | 9 +-
src/nominatim_db/clicmd/admin.py | 2 -
src/nominatim_db/clicmd/api.py | 31 ++---
src/nominatim_db/clicmd/args.py | 8 +-
src/nominatim_db/clicmd/convert.py | 6 -
src/nominatim_db/clicmd/export.py | 31 ++---
src/nominatim_db/clicmd/freeze.py | 7 +-
src/nominatim_db/clicmd/index.py | 9 +-
src/nominatim_db/clicmd/refresh.py | 11 +-
src/nominatim_db/clicmd/replication.py | 10 --
src/nominatim_db/clicmd/setup.py | 62 ++++-----
src/nominatim_db/clicmd/special_phrases.py | 7 +-
src/nominatim_db/config.py | 21 +---
src/nominatim_db/data/country_info.py | 10 +-
src/nominatim_db/data/place_info.py | 12 +-
src/nominatim_db/data/place_name.py | 6 +-
src/nominatim_db/data/postcode_format.py | 7 +-
src/nominatim_db/db/connection.py | 17 +--
src/nominatim_db/db/properties.py | 1 +
src/nominatim_db/db/query_pool.py | 6 +-
src/nominatim_db/db/sql_preprocessor.py | 8 +-
src/nominatim_db/db/utils.py | 2 +
src/nominatim_db/errors.py | 1 +
src/nominatim_db/indexer/indexer.py | 10 +-
src/nominatim_db/indexer/progress.py | 1 +
src/nominatim_db/indexer/runners.py | 14 +--
src/nominatim_db/tokenizer/base.py | 18 +--
src/nominatim_db/tokenizer/factory.py | 1 +
src/nominatim_db/tokenizer/icu_rule_loader.py | 14 +--
.../tokenizer/icu_token_analysis.py | 6 +-
src/nominatim_db/tokenizer/icu_tokenizer.py | 119 ++++++------------
src/nominatim_db/tokenizer/place_sanitizer.py | 1 -
src/nominatim_db/tokenizer/sanitizers/base.py | 1 -
.../sanitizers/clean_housenumbers.py | 4 +-
.../tokenizer/sanitizers/clean_postcodes.py | 9 +-
.../tokenizer/sanitizers/clean_tiger_tags.py | 1 +
.../tokenizer/sanitizers/config.py | 4 +-
.../tokenizer/sanitizers/delete_tags.py | 5 +-
.../tokenizer/sanitizers/split_name_list.py | 1 +
.../sanitizers/tag_analyzer_by_language.py | 9 +-
.../tokenizer/sanitizers/tag_japanese.py | 5 +
.../tokenizer/token_analysis/base.py | 1 +
.../token_analysis/config_variants.py | 3 +-
.../tokenizer/token_analysis/generic.py | 9 +-
.../token_analysis/generic_mutation.py | 3 +-
.../tokenizer/token_analysis/housenumbers.py | 8 +-
.../tokenizer/token_analysis/postcodes.py | 12 +-
src/nominatim_db/tools/add_osm_data.py | 1 +
src/nominatim_db/tools/admin.py | 1 +
src/nominatim_db/tools/check_database.py | 15 ++-
src/nominatim_db/tools/collect_os_info.py | 10 +-
src/nominatim_db/tools/convert_sqlite.py | 15 +--
src/nominatim_db/tools/database_import.py | 5 +-
src/nominatim_db/tools/exec_utils.py | 3 +-
src/nominatim_db/tools/freeze.py | 3 +-
src/nominatim_db/tools/migration.py | 5 +-
src/nominatim_db/tools/postcodes.py | 13 +-
src/nominatim_db/tools/refresh.py | 6 +-
src/nominatim_db/tools/replication.py | 8 +-
.../special_phrases/importer_statistics.py | 1 +
.../tools/special_phrases/sp_csv_loader.py | 3 +-
.../tools/special_phrases/sp_importer.py | 9 +-
.../tools/special_phrases/sp_wiki_loader.py | 12 +-
.../tools/special_phrases/special_phrase.py | 7 +-
src/nominatim_db/tools/tiger_data.py | 8 +-
src/nominatim_db/typing.py | 5 +-
src/nominatim_db/utils/centroid.py | 3 +-
src/nominatim_db/utils/url_utils.py | 5 +-
src/nominatim_db/version.py | 5 +-
112 files changed, 656 insertions(+), 1109 deletions(-)
delete mode 100644 .pylintrc
diff --git a/.pylintrc b/.pylintrc
deleted file mode 100644
index e562055d..00000000
--- a/.pylintrc
+++ /dev/null
@@ -1,22 +0,0 @@
-[MASTER]
-
-extension-pkg-whitelist=osmium,falcon
-ignored-modules=icu,datrie
-
-[MESSAGES CONTROL]
-
-[TYPECHECK]
-
-# closing added here because it sometimes triggers a false positive with
-# 'with' statements.
-ignored-classes=NominatimArgs,closing
-# 'too-many-ancestors' is triggered already by deriving from UserDict
-# 'not-context-manager' disabled because it causes false positives once
-# typed Python is enabled. See also https://github.com/PyCQA/pylint/issues/5273
-disable=too-few-public-methods,duplicate-code,too-many-ancestors,bad-option-value,no-self-use,not-context-manager,use-dict-literal,chained-comparison,attribute-defined-outside-init,too-many-boolean-expressions,contextmanager-generator-missing-cleanup,too-many-positional-arguments
-
-good-names=i,j,x,y,m,t,fd,db,cc,x1,x2,y1,y2,pt,k,v,nr
-
-[DESIGN]
-
-max-returns=7
diff --git a/src/nominatim_api/config.py b/src/nominatim_api/config.py
index 18afda66..94f3bb5d 100644
--- a/src/nominatim_api/config.py
+++ b/src/nominatim_api/config.py
@@ -8,5 +8,5 @@
# This file is just a placeholder to make the config module available
# during development. It will be replaced by nominatim_db/config.py on
# installation.
-# pylint: skip-file
+# flake8: noqa
from nominatim_db.config import *
diff --git a/src/nominatim_api/connection.py b/src/nominatim_api/connection.py
index 167ffaa4..e104745e 100644
--- a/src/nominatim_api/connection.py
+++ b/src/nominatim_api/connection.py
@@ -21,6 +21,7 @@ from .logging import log
T = TypeVar('T')
+
class SearchConnection:
""" An extended SQLAlchemy connection class, that also contains
the table definitions. The underlying asynchronous SQLAlchemy
@@ -32,37 +33,32 @@ class SearchConnection:
tables: SearchTables,
properties: Dict[str, Any]) -> None:
self.connection = conn
- self.t = tables # pylint: disable=invalid-name
+ self.t = tables
self._property_cache = properties
self._classtables: Optional[Set[str]] = None
self.query_timeout: Optional[int] = None
-
def set_query_timeout(self, timeout: Optional[int]) -> None:
""" Set the timeout after which a query over this connection
is cancelled.
"""
self.query_timeout = timeout
-
async def scalar(self, sql: sa.sql.base.Executable,
- params: Union[Mapping[str, Any], None] = None
- ) -> Any:
+ params: Union[Mapping[str, Any], None] = None) -> Any:
""" Execute a 'scalar()' query on the connection.
"""
log().sql(self.connection, sql, params)
return await asyncio.wait_for(self.connection.scalar(sql, params), self.query_timeout)
-
async def execute(self, sql: 'sa.Executable',
params: Union[Mapping[str, Any], Sequence[Mapping[str, Any]], None] = None
- ) -> 'sa.Result[Any]':
+ ) -> 'sa.Result[Any]':
""" Execute a 'execute()' query on the connection.
"""
log().sql(self.connection, sql, params)
return await asyncio.wait_for(self.connection.execute(sql, params), self.query_timeout)
-
async def get_property(self, name: str, cached: bool = True) -> str:
""" Get a property from Nominatim's property table.
@@ -89,7 +85,6 @@ class SearchConnection:
return cast(str, value)
-
async def get_db_property(self, name: str) -> Any:
""" Get a setting from the database. At the moment, only
'server_version', the version of the database software, can
@@ -102,7 +97,6 @@ class SearchConnection:
return self._property_cache['DB:server_version']
-
async def get_cached_value(self, group: str, name: str,
factory: Callable[[], Awaitable[T]]) -> T:
""" Access the cache for this Nominatim instance.
@@ -125,7 +119,6 @@ class SearchConnection:
return value
-
async def get_class_table(self, cls: str, typ: str) -> Optional[SaFromClause]:
""" Lookup up if there is a classtype table for the given category
and return a SQLAlchemy table for it, if it exists.
diff --git a/src/nominatim_api/core.py b/src/nominatim_api/core.py
index ff0db39f..3f4652bf 100644
--- a/src/nominatim_api/core.py
+++ b/src/nominatim_api/core.py
@@ -7,7 +7,7 @@
"""
Implementation of classes for API access via libraries.
"""
-from typing import Mapping, Optional, Any, AsyncIterator, Dict, Sequence, List,\
+from typing import Mapping, Optional, Any, AsyncIterator, Dict, Sequence, List, \
Union, Tuple, cast
import asyncio
import sys
@@ -21,7 +21,7 @@ from .errors import UsageError
from .sql.sqlalchemy_schema import SearchTables
from .sql.async_core_library import PGCORE_LIB, PGCORE_ERROR
from .config import Configuration
-from .sql import sqlite_functions, sqlalchemy_functions #pylint: disable=unused-import
+from .sql import sqlite_functions, sqlalchemy_functions # noqa
from .connection import SearchConnection
from .status import get_status, StatusResult
from .lookup import get_detailed_place, get_simple_place
@@ -31,7 +31,7 @@ from . import types as ntyp
from .results import DetailedResult, ReverseResult, SearchResults
-class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
+class NominatimAPIAsync:
""" The main frontend to the Nominatim database implements the
functions for lookup, forward and reverse geocoding using
asynchronous functions.
@@ -61,19 +61,18 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
"""
self.config = Configuration(project_dir, environ)
self.query_timeout = self.config.get_int('QUERY_TIMEOUT') \
- if self.config.QUERY_TIMEOUT else None
+ if self.config.QUERY_TIMEOUT else None
self.reverse_restrict_to_country_area = self.config.get_bool('SEARCH_WITHIN_COUNTRIES')
self.server_version = 0
if sys.version_info >= (3, 10):
self._engine_lock = asyncio.Lock()
else:
- self._engine_lock = asyncio.Lock(loop=loop) # pylint: disable=unexpected-keyword-arg
+ self._engine_lock = asyncio.Lock(loop=loop)
self._engine: Optional[sa_asyncio.AsyncEngine] = None
self._tables: Optional[SearchTables] = None
self._property_cache: Dict[str, Any] = {'DB:server_version': 0}
-
async def setup_database(self) -> None:
""" Set up the SQL engine and connections.
@@ -95,7 +94,6 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
extra_args['max_overflow'] = 0
extra_args['pool_size'] = self.config.get_int('API_POOL_SIZE')
-
is_sqlite = self.config.DATABASE_DSN.startswith('sqlite:')
if is_sqlite:
@@ -156,10 +154,9 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
self._property_cache['DB:server_version'] = server_version
- self._tables = SearchTables(sa.MetaData()) # pylint: disable=no-member
+ self._tables = SearchTables(sa.MetaData())
self._engine = engine
-
async def close(self) -> None:
""" Close all active connections to the database. The NominatimAPIAsync
object remains usable after closing. If a new API functions is
@@ -168,15 +165,12 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
if self._engine is not None:
await self._engine.dispose()
-
async def __aenter__(self) -> 'NominatimAPIAsync':
return self
-
async def __aexit__(self, *_: Any) -> None:
await self.close()
-
@contextlib.asynccontextmanager
async def begin(self) -> AsyncIterator[SearchConnection]:
""" Create a new connection with automatic transaction handling.
@@ -194,7 +188,6 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
async with self._engine.begin() as conn:
yield SearchConnection(conn, self._tables, self._property_cache)
-
async def status(self) -> StatusResult:
""" Return the status of the database.
"""
@@ -207,7 +200,6 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
return status
-
async def details(self, place: ntyp.PlaceRef, **params: Any) -> Optional[DetailedResult]:
""" Get detailed information about a place in the database.
@@ -220,7 +212,6 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
await make_query_analyzer(conn)
return await get_detailed_place(conn, place, details)
-
async def lookup(self, places: Sequence[ntyp.PlaceRef], **params: Any) -> SearchResults:
""" Get simple information about a list of places.
@@ -234,7 +225,6 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
return SearchResults(filter(None,
[await get_simple_place(conn, p, details) for p in places]))
-
async def reverse(self, coord: ntyp.AnyPoint, **params: Any) -> Optional[ReverseResult]:
""" Find a place by its coordinates. Also known as reverse geocoding.
@@ -255,7 +245,6 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
self.reverse_restrict_to_country_area)
return await geocoder.lookup(coord)
-
async def search(self, query: str, **params: Any) -> SearchResults:
""" Find a place by free-text search. Also known as forward geocoding.
"""
@@ -266,13 +255,11 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
async with self.begin() as conn:
conn.set_query_timeout(self.query_timeout)
geocoder = ForwardGeocoder(conn, ntyp.SearchDetails.from_kwargs(params),
- self.config.get_int('REQUEST_TIMEOUT') \
- if self.config.REQUEST_TIMEOUT else None)
+ self.config.get_int('REQUEST_TIMEOUT')
+ if self.config.REQUEST_TIMEOUT else None)
phrases = [Phrase(PhraseType.NONE, p.strip()) for p in query.split(',')]
return await geocoder.lookup(phrases)
-
- # pylint: disable=too-many-arguments,too-many-branches
async def search_address(self, amenity: Optional[str] = None,
street: Optional[str] = None,
city: Optional[str] = None,
@@ -326,11 +313,10 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
details.layers |= ntyp.DataLayer.POI
geocoder = ForwardGeocoder(conn, details,
- self.config.get_int('REQUEST_TIMEOUT') \
- if self.config.REQUEST_TIMEOUT else None)
+ self.config.get_int('REQUEST_TIMEOUT')
+ if self.config.REQUEST_TIMEOUT else None)
return await geocoder.lookup(phrases)
-
async def search_category(self, categories: List[Tuple[str, str]],
near_query: Optional[str] = None,
**params: Any) -> SearchResults:
@@ -352,12 +338,11 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
await make_query_analyzer(conn)
geocoder = ForwardGeocoder(conn, details,
- self.config.get_int('REQUEST_TIMEOUT') \
- if self.config.REQUEST_TIMEOUT else None)
+ self.config.get_int('REQUEST_TIMEOUT')
+ if self.config.REQUEST_TIMEOUT else None)
return await geocoder.lookup_pois(categories, phrases)
-
class NominatimAPI:
""" This class provides a thin synchronous wrapper around the asynchronous
Nominatim functions. It creates its own event loop and runs each
@@ -382,7 +367,6 @@ class NominatimAPI:
self._loop = asyncio.new_event_loop()
self._async_api = NominatimAPIAsync(project_dir, environ, loop=self._loop)
-
def close(self) -> None:
""" Close all active connections to the database.
@@ -393,15 +377,12 @@ class NominatimAPI:
self._loop.run_until_complete(self._async_api.close())
self._loop.close()
-
def __enter__(self) -> 'NominatimAPI':
return self
-
def __exit__(self, *_: Any) -> None:
self.close()
-
@property
def config(self) -> Configuration:
""" Provide read-only access to the [configuration](Configuration.md)
@@ -427,7 +408,6 @@ class NominatimAPI:
"""
return self._loop.run_until_complete(self._async_api.status())
-
def details(self, place: ntyp.PlaceRef, **params: Any) -> Optional[DetailedResult]:
""" Get detailed information about a place in the database.
@@ -510,7 +490,6 @@ class NominatimAPI:
"""
return self._loop.run_until_complete(self._async_api.details(place, **params))
-
def lookup(self, places: Sequence[ntyp.PlaceRef], **params: Any) -> SearchResults:
""" Get simple information about a list of places.
@@ -587,7 +566,6 @@ class NominatimAPI:
"""
return self._loop.run_until_complete(self._async_api.lookup(places, **params))
-
def reverse(self, coord: ntyp.AnyPoint, **params: Any) -> Optional[ReverseResult]:
""" Find a place by its coordinates. Also known as reverse geocoding.
@@ -669,7 +647,6 @@ class NominatimAPI:
"""
return self._loop.run_until_complete(self._async_api.reverse(coord, **params))
-
def search(self, query: str, **params: Any) -> SearchResults:
""" Find a place by free-text search. Also known as forward geocoding.
@@ -769,8 +746,6 @@ class NominatimAPI:
return self._loop.run_until_complete(
self._async_api.search(query, **params))
-
- # pylint: disable=too-many-arguments
def search_address(self, amenity: Optional[str] = None,
street: Optional[str] = None,
city: Optional[str] = None,
@@ -888,7 +863,6 @@ class NominatimAPI:
self._async_api.search_address(amenity, street, city, county,
state, country, postalcode, **params))
-
def search_category(self, categories: List[Tuple[str, str]],
near_query: Optional[str] = None,
**params: Any) -> SearchResults:
diff --git a/src/nominatim_api/errors.py b/src/nominatim_api/errors.py
index c7331a89..98fe693d 100644
--- a/src/nominatim_api/errors.py
+++ b/src/nominatim_api/errors.py
@@ -8,6 +8,7 @@
Custom exception and error classes for Nominatim.
"""
+
class UsageError(Exception):
""" An error raised because of bad user input. This error will usually
not cause a stack trace to be printed unless debugging is enabled.
diff --git a/src/nominatim_api/localization.py b/src/nominatim_api/localization.py
index 5964bbee..bbf9225b 100644
--- a/src/nominatim_api/localization.py
+++ b/src/nominatim_api/localization.py
@@ -11,6 +11,7 @@ from typing import Mapping, List, Optional
import re
+
class Locales:
""" Helper class for localization of names.
@@ -28,24 +29,20 @@ class Locales:
self._add_lang_tags('official_name', 'short_name')
self._add_tags('official_name', 'short_name', 'ref')
-
def __bool__(self) -> bool:
return len(self.languages) > 0
-
def _add_tags(self, *tags: str) -> None:
for tag in tags:
self.name_tags.append(tag)
self.name_tags.append(f"_place_{tag}")
-
def _add_lang_tags(self, *tags: str) -> None:
for tag in tags:
for lang in self.languages:
self.name_tags.append(f"{tag}:{lang}")
self.name_tags.append(f"_place_{tag}:{lang}")
-
def display_name(self, names: Optional[Mapping[str, str]]) -> str:
""" Return the best matching name from a dictionary of names
containing different name variants.
@@ -64,7 +61,6 @@ class Locales:
# Nothing? Return any of the other names as a default.
return next(iter(names.values()))
-
@staticmethod
def from_accept_languages(langstr: str) -> 'Locales':
""" Create a localization object from a language list in the
diff --git a/src/nominatim_api/logging.py b/src/nominatim_api/logging.py
index 7df36ec1..1a6aef9b 100644
--- a/src/nominatim_api/logging.py
+++ b/src/nominatim_api/logging.py
@@ -49,41 +49,35 @@ class BaseLogger:
""" Start a new debug chapter for the given function and its parameters.
"""
-
def section(self, heading: str) -> None:
""" Start a new section with the given title.
"""
-
def comment(self, text: str) -> None:
""" Add a simple comment to the debug output.
"""
-
def var_dump(self, heading: str, var: Any) -> None:
""" Print the content of the variable to the debug output prefixed by
the given heading.
"""
-
def table_dump(self, heading: str, rows: Iterator[Optional[List[Any]]]) -> None:
""" Print the table generated by the generator function.
"""
-
def result_dump(self, heading: str, results: Iterator[Tuple[Any, Any]]) -> None:
""" Print a list of search results generated by the generator function.
"""
-
def sql(self, conn: AsyncConnection, statement: 'sa.Executable',
params: Union[Mapping[str, Any], Sequence[Mapping[str, Any]], None]) -> None:
""" Print the SQL for the given statement.
"""
def format_sql(self, conn: AsyncConnection, statement: 'sa.Executable',
- extra_params: Union[Mapping[str, Any],
- Sequence[Mapping[str, Any]], None]) -> str:
+ extra_params: Union[Mapping[str, Any], Sequence[Mapping[str, Any]], None]
+ ) -> str:
""" Return the compiled version of the statement.
"""
compiled = cast('sa.ClauseElement', statement).compile(conn.sync_engine)
@@ -108,7 +102,7 @@ class BaseLogger:
try:
sqlstr = re.sub(r'__\[POSTCOMPILE_[^]]*\]', '%s', sqlstr)
return sqlstr % tuple((repr(params.get(name, None))
- for name in compiled.positiontup)) # type: ignore
+ for name in compiled.positiontup)) # type: ignore
except TypeError:
return sqlstr
@@ -121,28 +115,26 @@ class BaseLogger:
assert conn.dialect.name == 'sqlite'
# params in positional order
- pparams = (repr(params.get(name, None)) for name in compiled.positiontup) # type: ignore
+ pparams = (repr(params.get(name, None)) for name in compiled.positiontup) # type: ignore
sqlstr = re.sub(r'__\[POSTCOMPILE_([^]]*)\]', '?', sqlstr)
sqlstr = re.sub(r"\?", lambda m: next(pparams), sqlstr)
return sqlstr
+
class HTMLLogger(BaseLogger):
""" Logger that formats messages in HTML.
"""
def __init__(self) -> None:
self.buffer = io.StringIO()
-
def _timestamp(self) -> None:
self._write(f'[{dt.datetime.now()}]
')
-
def get_buffer(self) -> str:
return HTML_HEADER + self.buffer.getvalue() + HTML_FOOTER
-
def function(self, func: str, **kwargs: Any) -> None:
self._timestamp()
self._write(f"Debug output for {func}()
\nParameters:
")
@@ -150,17 +142,14 @@ class HTMLLogger(BaseLogger):
self._write(f'- {name}
- {self._python_var(value)}
')
self._write('
')
-
def section(self, heading: str) -> None:
self._timestamp()
self._write(f"{heading}
")
-
def comment(self, text: str) -> None:
self._timestamp()
self._write(f"{text}
")
-
def var_dump(self, heading: str, var: Any) -> None:
self._timestamp()
if callable(var):
@@ -168,7 +157,6 @@ class HTMLLogger(BaseLogger):
self._write(f'{heading}
{self._python_var(var)}')
-
def table_dump(self, heading: str, rows: Iterator[Optional[List[Any]]]) -> None:
self._timestamp()
head = next(rows)
@@ -185,11 +173,11 @@ class HTMLLogger(BaseLogger):
self._write('')
self._write('')
-
def result_dump(self, heading: str, results: Iterator[Tuple[Any, Any]]) -> None:
""" Print a list of search results generated by the generator function.
"""
self._timestamp()
+
def format_osm(osm_object: Optional[Tuple[str, int]]) -> str:
if not osm_object:
return '-'
@@ -218,7 +206,6 @@ class HTMLLogger(BaseLogger):
total += 1
self._write(f'TOTAL: {total}')
-
def sql(self, conn: AsyncConnection, statement: 'sa.Executable',
params: Union[Mapping[str, Any], Sequence[Mapping[str, Any]], None]) -> None:
self._timestamp()
@@ -230,7 +217,6 @@ class HTMLLogger(BaseLogger):
else:
self._write(f'{html.escape(sqlstr)}
')
-
def _python_var(self, var: Any) -> str:
if CODE_HIGHLIGHT:
fmt = highlight(str(var), PythonLexer(), HtmlFormatter(nowrap=True))
@@ -238,7 +224,6 @@ class HTMLLogger(BaseLogger):
return f'{html.escape(str(var))}
'
-
def _write(self, text: str) -> None:
""" Add the raw text to the debug output.
"""
@@ -251,38 +236,31 @@ class TextLogger(BaseLogger):
def __init__(self) -> None:
self.buffer = io.StringIO()
-
def _timestamp(self) -> None:
self._write(f'[{dt.datetime.now()}]\n')
-
def get_buffer(self) -> str:
return self.buffer.getvalue()
-
def function(self, func: str, **kwargs: Any) -> None:
self._write(f"#### Debug output for {func}()\n\nParameters:\n")
for name, value in kwargs.items():
self._write(f' {name}: {self._python_var(value)}\n')
self._write('\n')
-
def section(self, heading: str) -> None:
self._timestamp()
self._write(f"\n# {heading}\n\n")
-
def comment(self, text: str) -> None:
self._write(f"{text}\n")
-
def var_dump(self, heading: str, var: Any) -> None:
if callable(var):
var = var()
self._write(f'{heading}:\n {self._python_var(var)}\n\n')
-
def table_dump(self, heading: str, rows: Iterator[Optional[List[Any]]]) -> None:
self._write(f'{heading}:\n')
data = [list(map(self._python_var, row)) if row else None for row in rows]
@@ -291,7 +269,7 @@ class TextLogger(BaseLogger):
maxlens = [max(len(d[i]) for d in data if d) for i in range(num_cols)]
tablewidth = sum(maxlens) + 3 * num_cols + 1
- row_format = '| ' +' | '.join(f'{{:<{l}}}' for l in maxlens) + ' |\n'
+ row_format = '| ' + ' | '.join(f'{{:<{ln}}}' for ln in maxlens) + ' |\n'
self._write('-'*tablewidth + '\n')
self._write(row_format.format(*data[0]))
self._write('-'*tablewidth + '\n')
@@ -303,7 +281,6 @@ class TextLogger(BaseLogger):
if data[-1]:
self._write('-'*tablewidth + '\n')
-
def result_dump(self, heading: str, results: Iterator[Tuple[Any, Any]]) -> None:
self._timestamp()
self._write(f'{heading}:\n')
@@ -318,18 +295,15 @@ class TextLogger(BaseLogger):
total += 1
self._write(f'TOTAL: {total}\n\n')
-
def sql(self, conn: AsyncConnection, statement: 'sa.Executable',
params: Union[Mapping[str, Any], Sequence[Mapping[str, Any]], None]) -> None:
self._timestamp()
sqlstr = '\n| '.join(textwrap.wrap(self.format_sql(conn, statement, params), width=78))
self._write(f"| {sqlstr}\n\n")
-
def _python_var(self, var: Any) -> str:
return str(var)
-
def _write(self, text: str) -> None:
self.buffer.write(text)
@@ -368,8 +342,8 @@ HTML_HEADER: str = """
Nominatim - Debug