The typing_extensions package is only necessary now when running mypy.
It won't be used at runtime anymore.
* [PostgreSQL](https://www.postgresql.org) (9.6+ will work, 11+ strongly recommended)
* [PostGIS](https://postgis.net) (2.2+ will work, 3.0+ strongly recommended)
* [Python 3](https://www.python.org/) (3.6+)
- * [Python Typing Extensions](https://github.com/python/typing_extensions)
* [Psycopg2](https://www.psycopg.org) (2.7+)
* [Python Dotenv](https://github.com/theskumar/python-dotenv)
* [psutil](https://github.com/giampaolo/psutil)
* [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer)
* [Pylint](https://pylint.org/) (CI always runs the latest version from pip)
* [mypy](http://mypy-lang.org/) (plus typing information for external libs)
+* [Python Typing Extensions](https://github.com/python/typing_extensions) (for Python < 3.9)
* [pytest](https://pytest.org)
The documentation is built with mkdocs:
import logging
from pathlib import Path
-from typing_extensions import Protocol
-
from nominatim.errors import UsageError
from nominatim.config import Configuration
+from nominatim.typing import Protocol
LOG = logging.getLogger()
import logging
import re
-from typing_extensions import TypedDict
-
from nominatim.db.connection import Connection
from nominatim.tools.exec_utils import get_url
from nominatim.errors import UsageError
+from nominatim.typing import TypedDict
LOG = logging.getLogger()
ISODATE_FORMAT = '%Y-%m-%dT%H:%M:%S'
from typing import Any, List
import functools
-from typing_extensions import Protocol
from psycopg2 import sql as pysql
import psycopg2.extras
from nominatim.data.place_info import PlaceInfo
from nominatim.tokenizer.base import AbstractAnalyzer
from nominatim.db.async_connection import DBConnection
-from nominatim.typing import Query, DictCursorResult, DictCursorResults
+from nominatim.typing import Query, DictCursorResult, DictCursorResults, Protocol
# pylint: disable=C0111
from typing import List, Tuple, Dict, Any, Optional, Iterable
from pathlib import Path
-from typing_extensions import Protocol
-
from nominatim.config import Configuration
from nominatim.data.place_info import PlaceInfo
+from nominatim.typing import Protocol
class AbstractAnalyzer(ABC):
""" The analyzer provides the functions for analysing names and building
"""
Helper class to create ICU rules from a configuration file.
"""
-from typing import Mapping, Any, Generic, Dict, Optional
+from typing import Mapping, Any, Dict, Optional
import importlib
import io
import json
from nominatim.errors import UsageError
from nominatim.tokenizer.place_sanitizer import PlaceSanitizer
from nominatim.tokenizer.icu_token_analysis import ICUTokenAnalysis
-from nominatim.tokenizer.token_analysis.base import AnalysisModule, Analyser, T_config
+from nominatim.tokenizer.token_analysis.base import AnalysisModule, Analyser
import nominatim.data.country_info
LOG = logging.getLogger()
def _setup_analysis(self) -> None:
""" Process the rules used for creating the various token analyzers.
"""
- self.analysis: Dict[Optional[str], TokenAnalyzerRule[Any]] = {}
+ self.analysis: Dict[Optional[str], TokenAnalyzerRule] = {}
if not isinstance(self.analysis_rules, list):
raise UsageError("Configuration section 'token-analysis' must be a list.")
return ';'.join(flatten_config_list(content, section)) + ';'
-class TokenAnalyzerRule(Generic[T_config]):
+class TokenAnalyzerRule:
""" Factory for a single analysis module. The class saves the configuration
and creates a new token analyzer on request.
"""
# Find the analysis module
module_name = 'nominatim.tokenizer.token_analysis.' \
+ _get_section(rules, 'analyzer').replace('-', '_')
- self._analysis_mod: AnalysisModule[T_config] = importlib.import_module(module_name)
+ self._analysis_mod: AnalysisModule = importlib.import_module(module_name)
# Load the configuration.
self.config = self._analysis_mod.configure(rules, normalization_rules)
"""
def __init__(self, norm_rules: str, trans_rules: str,
- analysis_rules: Mapping[Optional[str], 'TokenAnalyzerRule[Any]']):
+ analysis_rules: Mapping[Optional[str], 'TokenAnalyzerRule']):
self.normalizer = Transliterator.createFromRules("icu_normalization",
norm_rules)
trans_rules += ";[:Space:]+ > ' '"
"""
from typing import Optional, Dict, List, Mapping, Callable
-from typing_extensions import Protocol, Final
from nominatim.tokenizer.sanitizers.config import SanitizerConfig
from nominatim.data.place_info import PlaceInfo
+from nominatim.typing import Protocol, Final
class PlaceName:
""" A searchable name for a place together with properties.
"""
Common data types and protocols for analysers.
"""
-from typing import TypeVar, Mapping, List, Any
+from typing import Mapping, List, Any
-from typing_extensions import Protocol
-
-
-T_config = TypeVar('T_config') # pylint: disable=invalid-name
+from nominatim.typing import Protocol
class Analyser(Protocol):
""" Instance of the token analyser.
and transliterate the result.
"""
-class AnalysisModule(Protocol[T_config]):
+class AnalysisModule(Protocol):
""" Protocol for analysis modules.
"""
- def configure(self, rules: Mapping[str, Any], normalization_rules: str) -> T_config:
+ def configure(self, rules: Mapping[str, Any], normalization_rules: str) -> Any:
""" Prepare the configuration of the analysis module.
This function should prepare all data that can be shared
between instances of this analyser.
"""
- def create(self, normalizer: Any, transliterator: Any, config: T_config) -> Analyser:
+ def create(self, normalizer: Any, transliterator: Any, config: Any) -> Analyser:
""" Create a new instance of the analyser.
A separate instance of the analyser is created for each thread
when used in multi-threading context.
import logging
import re
-from typing_extensions import Protocol
-
from psycopg2.sql import Identifier, SQL
from nominatim.config import Configuration
from nominatim.tools.special_phrases.importer_statistics import SpecialPhrasesImporterStatistics
from nominatim.tools.special_phrases.special_phrase import SpecialPhrase
from nominatim.tokenizer.base import AbstractTokenizer
+from nominatim.typing import Protocol
LOG = logging.getLogger()
from typing import Any, Union, Mapping, TypeVar, Sequence, TYPE_CHECKING
# Generics varaible names do not confirm to naming styles, ignore globally here.
-# pylint: disable=invalid-name,abstract-method,multiple-statements,missing-class-docstring
+# pylint: disable=invalid-name,abstract-method,multiple-statements
+# pylint: disable=missing-class-docstring,useless-import-alias
if TYPE_CHECKING:
import psycopg2.sql
DictCursorResults = Sequence[DictCursorResult]
T_cursor = TypeVar('T_cursor', bound='psycopg2.extensions.cursor')
+
+# The following typing features require typing_extensions to work
+# on all supported Python versions.
+# Only require this for type checking but not for normal operations.
+
+if TYPE_CHECKING:
+ from typing_extensions import (Protocol as Protocol,
+ Final as Final,
+ TypedDict as TypedDict)
+else:
+ Protocol = object
+ Final = 'Final'
+ TypedDict = dict
# Some of the Python packages that come with Ubuntu 18.04 are too old, so
# install the latest version from pip:
- pip3 install --user python-dotenv datrie pyyaml psycopg2-binary typing-extensions
+ pip3 install --user python-dotenv datrie pyyaml psycopg2-binary
#
# System Configuration
python3-psycopg2 python3-psutil python3-jinja2 \
python3-icu python3-datrie python3-yaml python3-pip git
-# Nominatim uses some typing features only available in later Python versions.
-# Install the latest version of the backport package:
-
- pip3 install --user typing-extensions
-
#
# System Configuration
# ====================
postgresql-contrib-14 postgresql-14-postgis-3-scripts \
php php-pgsql php-intl libicu-dev python3-dotenv \
python3-psycopg2 python3-psutil python3-jinja2 \
- python3-typing-extensions \
python3-icu python3-datrie git
#