From 1f0796778754d8df0dfab9dd01302e26a397f064 Mon Sep 17 00:00:00 2001 From: Sarah Hoffmann Date: Sun, 10 Nov 2024 22:47:14 +0100 Subject: [PATCH 1/3] 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 e562055d2..000000000 --- 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 18afda668..94f3bb5d0 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 167ffaa45..e104745eb 100644 --- a/src/nominatim_api/connection.py +++ b/src/nominatim_api/connection.py @@ -21,6 +21,7 @@ T = TypeVar('T') + class SearchConnection: """ An extended SQLAlchemy connection class, that also contains the table definitions. The underlying asynchronous SQLAlchemy @@ -32,37 +33,32 @@ def __init__(self, conn: AsyncConnection, 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 @@ async def get_property(self, name: str, cached: bool = True) -> str: 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 @@ async def get_db_property(self, name: str) -> Any: 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 @@ async def get_cached_value(self, group: str, name: str, 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 ff0db39f8..3f4652bff 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 .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 .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 @@ def __init__(self, project_dir: Optional[Union[str, Path]] = None, """ 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 @@ async def setup_database(self) -> None: 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 @@ def _on_connect(dbapi_con: Any, _: Any) -> None: 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 @@ async def close(self) -> None: 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 @@ async def begin(self) -> AsyncIterator[SearchConnection]: 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 @@ async def status(self) -> StatusResult: 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 @@ async def details(self, place: ntyp.PlaceRef, **params: Any) -> Optional[Detaile 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 @@ async def lookup(self, places: Sequence[ntyp.PlaceRef], **params: Any) -> Search 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 @@ async def reverse(self, coord: ntyp.AnyPoint, **params: Any) -> Optional[Reverse 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 @@ async def search(self, query: str, **params: Any) -> SearchResults: 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 @@ async def search_address(self, amenity: Optional[str] = None, 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 @@ async def search_category(self, categories: List[Tuple[str, str]], 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 @@ def __init__(self, project_dir: Optional[Union[str, Path]] = None, 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 @@ def close(self) -> None: 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 @@ def status(self) -> StatusResult: """ 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 @@ def details(self, place: ntyp.PlaceRef, **params: Any) -> Optional[DetailedResul """ 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 @@ def lookup(self, places: Sequence[ntyp.PlaceRef], **params: Any) -> SearchResult """ 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 @@ def reverse(self, coord: ntyp.AnyPoint, **params: Any) -> Optional[ReverseResult """ 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 @@ def search(self, query: str, **params: Any) -> SearchResults: 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 @@ def search_address(self, amenity: Optional[str] = None, 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 c7331a89f..98fe693d1 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 5964bbee8..bbf9225bb 100644 --- a/src/nominatim_api/localization.py +++ b/src/nominatim_api/localization.py @@ -11,6 +11,7 @@ import re + class Locales: """ Helper class for localization of names. @@ -28,24 +29,20 @@ def __init__(self, langs: Optional[List[str]] = None): 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 @@ def display_name(self, names: Optional[Mapping[str, str]]) -> str: # 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 7df36ec12..1a6aef9b5 100644 --- a/src/nominatim_api/logging.py +++ b/src/nominatim_api/logging.py @@ -49,41 +49,35 @@ def function(self, func: str, **kwargs: Any) -> None: """ 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 @@ def format_sql(self, conn: AsyncConnection, statement: 'sa.Executable', 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 @@ def format_sql(self, conn: AsyncConnection, statement: 'sa.Executable', 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}()

\n

Parameters:

") @@ -150,17 +142,14 @@ def function(self, func: str, **kwargs: Any) -> None: 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 @@ def var_dump(self, heading: str, var: Any) -> None: 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 @@ def table_dump(self, heading: str, rows: Iterator[Optional[List[Any]]]) -> None: 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 @@ def format_osm(osm_object: Optional[Tuple[str, int]]) -> str: 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 @@ def sql(self, conn: AsyncConnection, statement: 'sa.Executable', 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 @@ def _python_var(self, var: Any) -> str: 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 @@ def table_dump(self, heading: str, rows: Iterator[Optional[List[Any]]]) -> None: 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 @@ def table_dump(self, heading: str, rows: Iterator[Optional[List[Any]]]) -> None: 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 @@ def result_dump(self, heading: str, results: Iterator[Tuple[Any, Any]]) -> None: 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 @@ def get_and_disable() -> str: Nominatim - Debug