sibi-dst 0.3.32__py3-none-any.whl → 0.3.33__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,6 +10,28 @@ apps_label = "datacubes"
10
10
 
11
11
 
12
12
  class SqlAlchemyModelBuilder:
13
+ """
14
+ Provides functionality for building SQLAlchemy ORM models dynamically from
15
+ reflected database tables. This class is intended for use with a SQLAlchemy
16
+ engine and metadata to automatically generate ORM models for specified
17
+ database tables.
18
+
19
+ The primary purpose of this class is to simplify the process of creating
20
+ SQLAlchemy ORM models by reflecting tables from a connected database,
21
+ dynamically generating model classes, and handling relationships between
22
+ tables.
23
+
24
+ :ivar engine: SQLAlchemy engine connected to the database.
25
+ :type engine: Engine
26
+ :ivar table_name: Name of the table for which the model is generated.
27
+ :type table_name: str
28
+ :ivar metadata: SQLAlchemy MetaData instance for reflecting tables.
29
+ :type metadata: MetaData
30
+ :ivar table: Reflected SQLAlchemy Table object for the specified table name.
31
+ :type table: Optional[Table]
32
+ :ivar class_name: Dynamically normalized class name derived from table_name.
33
+ :type class_name: str
34
+ """
13
35
  _model_cache = {} # Local cache for model classes
14
36
 
15
37
  def __init__(self, engine, table_name):
@@ -27,6 +49,16 @@ class SqlAlchemyModelBuilder:
27
49
  self.class_name = self.normalize_class_name(self.table_name)
28
50
 
29
51
  def build_model(self) -> type:
52
+ """
53
+ Builds and returns a database model class corresponding to the specified table name.
54
+ The method checks if the model is already registered in the ORM's registry. If not,
55
+ it reflects the database schema of the specified table and dynamically creates the
56
+ model class.
57
+
58
+ :raises ValueError: If the specified table does not exist in the database.
59
+ :return: A database model class corresponding to the specified table name.
60
+ :rtype: type
61
+ """
30
62
  # Check if the model is already registered
31
63
  model = Base.registry._class_registry.get(self.class_name)
32
64
  if model:
@@ -42,10 +74,17 @@ class SqlAlchemyModelBuilder:
42
74
 
43
75
  def create_model(self) -> type:
44
76
  """
45
- Create a SQLAlchemy ORM model for the reflected table.
77
+ Generates a SQLAlchemy model class dynamically based on the specified table and
78
+ its columns. The method extracts column information, defines the necessary
79
+ attributes, and creates the model class if it doesn't already exist in the
80
+ SQLAlchemy base registry.
46
81
 
47
- Returns:
48
- type: Dynamically generated SQLAlchemy ORM model class.
82
+ :raises KeyError: If the table or table name does not exist in the provided
83
+ schema.
84
+ :raises Exception: If the model creation fails for any reason.
85
+
86
+ :return: The dynamically created or fetched model class.
87
+ :rtype: type
49
88
  """
50
89
  # Normalize the class name from the table name
51
90
  columns = self.get_columns(self.table)
@@ -70,13 +109,17 @@ class SqlAlchemyModelBuilder:
70
109
 
71
110
  def get_columns(self, table: Table):
72
111
  """
73
- Extract columns from the table and create corresponding SQLAlchemy fields.
74
-
75
- Args:
76
- table (Table): SQLAlchemy Table object.
77
-
78
- Returns:
79
- dict: Dictionary of column attributes.
112
+ Extracts and returns a dictionary of column names and their corresponding column
113
+ objects from a given table, excluding reserved names. Reserved names are used
114
+ internally and should not overlap with column names in the provided table. The
115
+ method ensures sanitized column names through normalization and filters out any
116
+ column matching reserved keywords.
117
+
118
+ :param table: The table object from which columns are to be extracted.
119
+ :type table: Table
120
+ :return: A dictionary containing the sanitized column names as keys and their
121
+ corresponding column objects as values, excluding reserved names.
122
+ :rtype: dict
80
123
  """
81
124
  columns = {}
82
125
  reserved_names = ["metadata", "class_", "table"]
@@ -89,11 +132,18 @@ class SqlAlchemyModelBuilder:
89
132
 
90
133
  def add_relationships(self, attrs, table: Table):
91
134
  """
92
- Add relationships to the model for foreign keys.
93
-
94
- Args:
95
- attrs (dict): Attributes of the dynamically created model.
96
- table (Table): SQLAlchemy Table object.
135
+ Adds relationships to the provided attributes dictionary for a given database table.
136
+
137
+ This method iterates through the foreign keys of the provided table, constructs
138
+ relationship attributes, and updates the attributes dictionary with relationships
139
+ that connect the current table to related tables.
140
+
141
+ :param attrs: Dictionary of attributes to which relationships will be added.
142
+ The dictionary will be updated with new relationship mappings.
143
+ :type attrs: dict
144
+ :param table: A database table object containing foreign key relationships.
145
+ The method will use this table to establish relationships.
146
+ :return: None
97
147
  """
98
148
  for fk in table.foreign_keys:
99
149
  related_table_name = fk.column.table.name
@@ -104,26 +154,37 @@ class SqlAlchemyModelBuilder:
104
154
  @staticmethod
105
155
  def normalize_class_name(table_name: str) -> str:
106
156
  """
107
- Normalize a table name into a valid Python class name.
108
-
109
- Args:
110
- table_name (str): Name of the table.
111
-
112
- Returns:
113
- str: Normalized class name.
157
+ Generate a normalized class name from a given table name by capitalizing
158
+ each word separated by underscores and concatenating them.
159
+
160
+ This static method takes a string representation of a table name, where
161
+ words are separated by underscores, and converts it into a camel case
162
+ class name. It processes the string by capitalizing the first letter of
163
+ each word and removing the underscores. The normalized class name
164
+ returned can be used programmatically for various purposes, such as
165
+ class generation or naming conventions.
166
+
167
+ :param table_name: The table name to normalize, with words separated by
168
+ underscores. E.g., 'sample_table' becomes 'SampleTable'.
169
+ :type table_name: str
170
+ :return: A normalized class name in camel case format.
171
+ :rtype: str
114
172
  """
115
173
  return "".join(word.capitalize() for word in table_name.split("_"))
116
174
 
117
175
  @staticmethod
118
176
  def normalize_column_name(column_name: str) -> str:
119
177
  """
120
- Normalize a column name into a valid Python identifier.
121
-
122
- Args:
123
- column_name (str): Name of the column.
124
-
125
- Returns:
126
- str: Normalized column name.
178
+ Normalize a column name by replacing any non-word characters or leading numbers
179
+ with underscores, while ensuring it does not conflict with reserved keywords
180
+ such as 'class', 'def', 'return', etc. If the normalized name conflicts with
181
+ a Python reserved keyword, "_field" is appended to it.
182
+
183
+ :param column_name: The original name of the column to be normalized.
184
+ :type column_name: str
185
+ :return: A normalized column name that is safe and compatible for usage
186
+ in various contexts such as database columns or Python code.
187
+ :rtype: str
127
188
  """
128
189
  column_name = re.sub(r"\W|^(?=\d)", "_", column_name)
129
190
  if column_name in {"class", "def", "return", "yield", "global"}:
@@ -27,6 +27,36 @@ LOOKUP_SEP = "__"
27
27
 
28
28
 
29
29
  class ParamsConfig(BaseModel):
30
+ """
31
+ Defines a configuration model for parameters with functionality for parsing,
32
+ validation, and conversion of legacy filters.
33
+
34
+ This class extends BaseModel from Pydantic and is designed to handle multiple
35
+ sets of configurations, including field mappings, filters, dataframe parameters,
36
+ and dataframe options. It allows for flexible parsing of parameters across a
37
+ variety of supported structures and ensures that legacy filters can be
38
+ appropriately converted for compatibility.
39
+
40
+ :ivar field_map: Maps field names to their equivalent legacy field names.
41
+ :type field_map: Optional[Dict]
42
+ :ivar legacy_filters: Indicates whether legacy filters should be processed.
43
+ :type legacy_filters: bool
44
+ :ivar sticky_filters: Stores additional filters as key-value pairs that persist
45
+ across parameter parsing.
46
+ :type sticky_filters: Dict[str, Union[str, bool, int, float, list, tuple]]
47
+ :ivar filters: Holds all the current filters including sticky and dynamically
48
+ parsed filters.
49
+ :type filters: Dict[str, Union[str, Dict, bool, int, float, list, tuple]]
50
+ :ivar df_params: Contains parameters related to dataframe configurations in a
51
+ structured format.
52
+ :type df_params: Dict[str, Union[tuple, str, bool, None]]
53
+ :ivar df_options: Stores optional configurations for a dataframe, allowing for
54
+ additional behavior customization.
55
+ :type df_options: Dict[str, Union[bool, str, None]]
56
+ :ivar params: Dictionary of parameters provided for configuration, supporting
57
+ both basic and nested structures.
58
+ :type params: Dict[str, Union[str, bool, int, float, List[Union[str, int, bool, float]]]]
59
+ """
30
60
  field_map: Optional[Dict] = Field(default_factory=dict)
31
61
  legacy_filters: bool = False
32
62
  sticky_filters: Dict[str, Union[str, bool, int, float, list, tuple]] = Field(default_factory=dict)
@@ -42,6 +72,17 @@ class ParamsConfig(BaseModel):
42
72
  return self
43
73
 
44
74
  def parse_params(self, params):
75
+ """
76
+ Parses and separates the given parameters into specific categories such as dataframe parameters,
77
+ dataframe options, and filters. Updates existing class attributes with the parsed values,
78
+ retaining any sticky filters. Also handles the legacy filters if provided.
79
+
80
+ :param params: Dictionary containing parameters to process. These parameters can include specific
81
+ keys relevant for dataframe configuration (e.g., dataframe parameters, dataframe options)
82
+ as well as arbitrary filter settings.
83
+ :type params: dict
84
+ :return: None
85
+ """
45
86
  self.legacy_filters = params.pop('legacy_filters', self.legacy_filters)
46
87
  self.field_map = params.pop('field_map', self.field_map)
47
88
  self.sticky_filters = params.pop('params', self.sticky_filters)
@@ -60,6 +101,24 @@ class ParamsConfig(BaseModel):
60
101
  self.convert_legacy_filters()
61
102
 
62
103
  def convert_legacy_filters(self):
104
+ """
105
+ Converts legacy filter fields in the `self.filters` dictionary to their
106
+ modern equivalents using the mappings provided in `self.field_map`.
107
+ This method ensures backward compatibility for filters by automatically
108
+ translating the old field names into the current system.
109
+
110
+ The function first verifies that the required dictionaries (`legacy_filters`,
111
+ `field_map`, `filters`) are valid. It creates a reverse map of `field_map` for
112
+ efficient lookup, processes the key names within `self.filters`, and updates
113
+ them to reflect the legacy mapping.
114
+
115
+ :raises KeyError: If any required dictionary key is missing during processing.
116
+
117
+ :param self.legacy_filters: A boolean flag indicating whether legacy filters
118
+ are being used.
119
+ :type self.legacy_filters: bool
120
+
121
+ """
63
122
  if not self.legacy_filters or not self.field_map or not self.filters:
64
123
  return
65
124
  # create a reverse map of the field_map
@@ -8,6 +8,20 @@ app_geo_locator_test_place = os.environ.get('GEO_LOCATOR_TEST_PLACE', "San Jose,
8
8
 
9
9
 
10
10
  class GeolocationService:
11
+ """
12
+ Provides geolocation services, such as forward and reverse geocoding.
13
+
14
+ This class is intended to interface with a geocoding service (e.g., Nominatim)
15
+ for performing geocoding operations. It initializes the geolocation service
16
+ based on a provided or default configuration and provides methods for geocoding
17
+ addresses or retrieving addresses from coordinates.
18
+
19
+ :ivar geolocator: Instance of the geocoding service used for geolocation tasks.
20
+ Will be `None` if initialization fails or is incomplete.
21
+ :type geolocator: Optional[Nominatim]
22
+ :ivar debug: Indicates whether debug messages are enabled.
23
+ :type debug: bool
24
+ """
11
25
  debug: bool = False
12
26
 
13
27
  def __init__(self, debug=False):
@@ -5,6 +5,16 @@ geolocator = None
5
5
 
6
6
 
7
7
  def get_geolocator():
8
+ """
9
+ Provides a function to instantiate or retrieve a global geolocator instance
10
+ using the GeolocationService class. If the geolocator has already been
11
+ created, it will return the original global instance. Otherwise, it initializes
12
+ a new instance of the GeolocationService with debugging enabled and stores it
13
+ globally.
14
+
15
+ :return: The global instance of the GeolocationService
16
+ :rtype: GeolocationService
17
+ """
8
18
  global geolocator
9
19
  if geolocator is None:
10
20
  geolocator = GeolocationService(debug=True)
@@ -15,6 +25,23 @@ def get_geolocator():
15
25
 
16
26
 
17
27
  def get_address_by_coordinates(latitude, longitude, exactly_one=True):
28
+ """
29
+ Retrieves the address based on the provided geographic coordinates (latitude and
30
+ longitude). Utilizes the geopy library's geolocator to find and reverse-geocode
31
+ the location associated with the given coordinates. Returns a human-readable
32
+ address if available or an error message for specific conditions.
33
+
34
+ :param latitude: The latitude of the location to find the address for.
35
+ :type latitude: float
36
+ :param longitude: The longitude of the location to find the address for.
37
+ :type longitude: float
38
+ :param exactly_one: If true, ensures exactly one result is returned. If false,
39
+ returns a list of possible matches. Defaults to True.
40
+ :type exactly_one: bool, optional
41
+ :return: A string containing the human-readable address of the location or an
42
+ error message in case of failure.
43
+ :rtype: str
44
+ """
18
45
  geolocator = get_geolocator()
19
46
  try:
20
47
  location = geolocator.reverse((latitude, longitude), exactly_one=exactly_one)
@@ -28,10 +55,17 @@ def get_address_by_coordinates(latitude, longitude, exactly_one=True):
28
55
 
29
56
  def get_coordinates_for_address(address):
30
57
  """
31
- Geocode an address using a custom Nominatim server.
58
+ Gets geographical coordinates (latitude and longitude) along with the full formatted
59
+ address for a given address string. Makes use of a geolocation service to retrieve
60
+ the data and handles possible exceptions during the process.
61
+
62
+ :param address: The address as a string for which coordinates need to be determined.
63
+ :type address: str
32
64
 
33
- :param address: The address to geocode.
34
- :return: A dictionary with the location's latitude, longitude, and full address, or a message if an error occurs.
65
+ :return: A dictionary containing the full formatted address, latitude, and longitude
66
+ if the location is found. Otherwise, returns a string describing an error
67
+ or that no location was found.
68
+ :rtype: dict or str
35
69
  """
36
70
  geolocator = get_geolocator()
37
71
  try:
@@ -11,6 +11,64 @@ from folium.plugins import Fullscreen
11
11
 
12
12
 
13
13
  class BaseOsmMap:
14
+ """
15
+ BaseOsmMap class serves as a foundational class for creating and managing maps
16
+ using OpenStreetMap data. It integrates features from libraries like osmnx and
17
+ folium to facilitate visualization, tile layer management, bounding box handling,
18
+ and nearest node calculation for geographic coordinates.
19
+
20
+ The class is designed to be subclassed, enabling customization of map processing
21
+ logic while providing core functionalities needed for map creation and manipulation.
22
+
23
+ :ivar tile_options: Dictionary containing options for pre-defined tile layers.
24
+ Keys represent display names while values represent tile layer configurations.
25
+ :type tile_options: dict
26
+ :ivar bounds: Default map bounds representing geographical extents for Costa Rica.
27
+ :type bounds: list[list[float]]
28
+ :ivar osmnx_graph: Input graph representing OpenStreetMap network data, used for
29
+ operations like subgraph extraction and nearest node calculation.
30
+ :type osmnx_graph: networkx.classes.multidigraph.MultiDiGraph
31
+ :ivar df: DataFrame containing data points with geographic coordinates. It must
32
+ not be empty and should include latitude and longitude columns as specified
33
+ in `lat_col` and `lon_col`.
34
+ :type df: pandas.DataFrame
35
+ :ivar lat_col: Name of the column in `df` representing latitude coordinates of data points.
36
+ :type lat_col: str
37
+ :ivar lon_col: Name of the column in `df` representing longitude coordinates of data points.
38
+ :type lon_col: str
39
+ :ivar osm_map: Folium Map object that serves as a container for geographic visualization.
40
+ This is dynamically initialized based on the provided data.
41
+ :type osm_map: folium.Map
42
+ :ivar G: Subgraph of the provided `osmnx_graph`, extracted based on bounding box
43
+ derived from the input data.
44
+ :type G: networkx.classes.multidigraph.MultiDiGraph
45
+ :ivar map_html_title: HTML-escaped title for map visualization, shown on the interactive map.
46
+ :type map_html_title: str
47
+ :ivar zoom_start: Initial zoom level for the map when rendered.
48
+ :type zoom_start: int
49
+ :ivar fullscreen: Boolean option to enable or disable fullscreen control on the interactive map.
50
+ :type fullscreen: bool
51
+ :ivar fullscreen_position: Position of the fullscreen control on the map, e.g., 'topright'.
52
+ :type fullscreen_position: str
53
+ :ivar tiles: Default tile layer to be used for the map visualization.
54
+ :type tiles: str
55
+ :ivar verbose: Boolean flag indicating if verbose logging of operations should be enabled.
56
+ :type verbose: bool
57
+ :ivar sort_keys: Keys to sort the DataFrame by, if applicable, before processing.
58
+ :type sort_keys: list[str] or None
59
+ :ivar dt_field: Column name in `df` representing datetimes, if applicable, for specialized processing.
60
+ :type dt_field: str or None
61
+ :ivar dt: List of datetime objects extracted from `dt_field` in `df`, dynamically initialized.
62
+ :type dt: list[datetime.datetime] or None
63
+ :ivar calc_nearest_nodes: Boolean flag to indicate whether nearest nodes to the input
64
+ points should be calculated from `osmnx_graph`.
65
+ :type calc_nearest_nodes: bool
66
+ :ivar nearest_nodes: List of nearest node IDs for each point in the input data, if calculated.
67
+ :type nearest_nodes: list[int] or None
68
+ :ivar max_bounds: Boolean indicating whether bounds (default to Costa Rica) should be applied
69
+ to fit the map within those limits interactively.
70
+ :type max_bounds: bool
71
+ """
14
72
  tile_options = {
15
73
  "OpenStreetMap": "OpenStreetMap",
16
74
  "CartoDB": "cartodbpositron",
@@ -20,6 +78,47 @@ class BaseOsmMap:
20
78
  bounds = [[8.0340, -85.9417], [11.2192, -82.5566]]
21
79
 
22
80
  def __init__(self, osmnx_graph=None, df=None, **kwargs):
81
+ """
82
+ Initializes a map visualization handler with input parameters for managing and displaying
83
+ spatial data in conjunction with an OSMnx graph. It validates input parameters for completeness
84
+ and correctness, and configures internal attributes for the visualization of map layers.
85
+
86
+ :param osmnx_graph: The OSMnx graph to be used for spatial data processing.
87
+ :param df: The pandas DataFrame containing spatial data.
88
+ :param kwargs: Additional keyword arguments for customization.
89
+ :type osmnx_graph: object
90
+ :type df: pandas.DataFrame
91
+ :type kwargs: dict
92
+
93
+ :raises ValueError: If `osmnx_graph` is not provided.
94
+ :raises ValueError: If `df` is not provided.
95
+ :raises ValueError: If the provided `df` is empty.
96
+
97
+ :attribute df: A copy of the provided DataFrame.
98
+ :attribute osmnx_graph: The input OSMnx graph used for spatial data operations.
99
+ :attribute lat_col: The name of the column in `df` containing latitude values.
100
+ :attribute lon_col: The name of the column in `df` containing longitude values.
101
+ :attribute osm_map: Internal representation of the map; initialized to None.
102
+ :attribute G: Placeholder for graph-related data; initialized to None.
103
+ :attribute map_html_title: Sanitized HTML title to be used in rendered map outputs.
104
+ :attribute zoom_start: The initial zoom level for the map visualization (default: 13).
105
+ :attribute fullscreen: Boolean flag to enable fullscreen map display (default: True).
106
+ :attribute fullscreen_position: The position of the fullscreen control button
107
+ (default: 'topright').
108
+ :attribute tiles: The tile set to be used for the map visualization (default: 'OpenStreetMap').
109
+ :attribute verbose: Boolean flag for enabling verbose output (default: False).
110
+ :attribute sort_keys: Optional parameter dictating sorting order for keys (default: None).
111
+ :attribute dt_field: Optional name of the datetime field in the DataFrame (default: None).
112
+ :attribute dt: Placeholder for date/time data; initialized to None.
113
+ :attribute calc_nearest_nodes: Boolean flag to calculate nearest nodes to coordinates
114
+ (default: False).
115
+ :attribute nearest_nodes: Placeholder for nearest nodes data; initialized to None.
116
+ :attribute max_bounds: Boolean flag to restrict the map view to maximum bounds
117
+ (default: False).
118
+
119
+ :note: This class also initializes necessary internal functionalities including DataFrame
120
+ pre-processing (`_prepare_df`) and base map setup (`_initialise_map`).
121
+ """
23
122
  if osmnx_graph is None:
24
123
  raise ValueError('osmnx_graph must be provided')
25
124
  if df is None:
@@ -50,6 +149,21 @@ class BaseOsmMap:
50
149
 
51
150
 
52
151
  def _prepare_df(self):
152
+ """
153
+ Prepares the underlying DataFrame for further processing.
154
+
155
+ This method performs several operations on the DataFrame, such as sorting,
156
+ resetting the index, and extracting relevant columns into various lists.
157
+ Additionally, it calculates the nearest nodes from an OSMnx graph if
158
+ required. The operations are governed by instance attributes and their
159
+ current states.
160
+
161
+ :raises AttributeError: If required attributes for processing are not
162
+ correctly set or do not exist in the DataFrame.
163
+ :param self: Object that contains the DataFrame (df) and other related
164
+ attributes required for processing.
165
+ :return: None
166
+ """
53
167
  if self.sort_keys:
54
168
  self.df.sort_values(by=self.sort_keys, inplace=True)
55
169
  self.df.reset_index(drop=True, inplace=True)
@@ -63,6 +177,15 @@ class BaseOsmMap:
63
177
 
64
178
 
65
179
  def _initialise_map(self):
180
+ """
181
+ Initializes an OpenStreetMap (OSM) map instance and extracts a subgraph of map
182
+ data based on provided GPS points. The map's central location is calculated
183
+ as the mean of the latitudinal and longitudinal values of the GPS points.
184
+ Additionally, a bounding box is determined to extract the relevant section
185
+ of the map graph.
186
+
187
+ :return: None
188
+ """
66
189
  gps_array = np.array(self.gps_points)
67
190
  mean_latitude = np.mean(gps_array[:, 0])
68
191
  mean_longitude = np.mean(gps_array[:, 1])
@@ -73,6 +196,24 @@ class BaseOsmMap:
73
196
 
74
197
 
75
198
  def _attach_supported_tiles(self):
199
+ """
200
+ Attach supported tile layers from the provided tile options to the map object.
201
+
202
+ This method normalizes the default tile layer name and ensures that it is not
203
+ duplicated in the map by filtering out the default tile from the `tile_options`.
204
+ Then, it iterates over the filtered tile options and attaches each supported
205
+ tile layer to the map object using the folium library.
206
+
207
+ :raises KeyError: If any key in `tile_options` is invalid or not found.
208
+
209
+ :param self:
210
+ The instance of the class. It is expected to have the following attributes:
211
+ - tiles (str): The name of the default tile layer.
212
+ - tile_options (Dict[str, str]): A dictionary of tile layer names
213
+ and their associated URLs.
214
+ - osm_map (folium.Map): The map object to which tile layers are attached.
215
+ :return: None
216
+ """
76
217
  # Normalize the default tile name to lowercase for comparison
77
218
  normalized_default_tile = self.tiles.lower()
78
219
 
@@ -84,6 +225,22 @@ class BaseOsmMap:
84
225
 
85
226
 
86
227
  def _get_bounding_box_from_points(self, margin=0.001):
228
+ """
229
+ Calculate a bounding box from GPS points with an additional margin.
230
+
231
+ This method processes the GPS points in the `self.gps_points` list
232
+ and calculates a geographical bounding box encompassing all
233
+ points with an optional margin added to its boundaries. The
234
+ bounding box is defined by the northernmost, southernmost,
235
+ easternmost, and westernmost boundaries.
236
+
237
+ :param margin: A float value that adds a margin to the bounding
238
+ box boundaries.
239
+ Defaults to 0.001.
240
+ :return: A tuple containing four float values in the order:
241
+ north (northernmost boundary), south (southernmost boundary),
242
+ east (easternmost boundary), and west (westernmost boundary).
243
+ """
87
244
  latitudes = [point[0] for point in self.gps_points]
88
245
  longitudes = [point[1] for point in self.gps_points]
89
246
 
@@ -96,6 +253,26 @@ class BaseOsmMap:
96
253
 
97
254
 
98
255
  def _extract_subgraph(self, north, south, east, west):
256
+ """
257
+ Extracts a subgraph from the OSMnx graph based on a specified bounding box.
258
+
259
+ This function takes the northern, southern, eastern, and western bounds to
260
+ define a geographic bounding box. It creates a polygon from these bounds and
261
+ identifies nodes within the graph that fall within this boundary. A new subgraph
262
+ is then created using these identified nodes. This functionality supports different
263
+ approaches depending on the OSMnx version.
264
+
265
+ :param north: The northern boundary of the bounding box.
266
+ :type north: float
267
+ :param south: The southern boundary of the bounding box.
268
+ :type south: float
269
+ :param east: The eastern boundary of the bounding box.
270
+ :type east: float
271
+ :param west: The western boundary of the bounding box.
272
+ :type west: float
273
+ :return: A subgraph extracted from the OSMnx graph containing nodes within the bounding box.
274
+ :rtype: networkx.Graph
275
+ """
99
276
  # Create a bounding box polygon
100
277
  # from osmnx v2 this is how it is done
101
278
  if ox.__version__ >= '2.0':
@@ -117,18 +294,45 @@ class BaseOsmMap:
117
294
 
118
295
  @abstractmethod
119
296
  def process_map(self):
297
+ """
298
+ This abstract method serves as a blueprint for processing a map. It is intentionally
299
+ left unimplemented and must be overridden in any concrete subclass. Subclasses should
300
+ provide their own specific logic for map processing by implementing this interface.
301
+
302
+ :return: None
303
+ """
120
304
  # this is to be implemented at the subclass level
121
305
  # implement here your specific map logic.
122
306
  ...
123
307
 
124
308
 
125
309
  def pre_process_map(self):
310
+ """
311
+ Pre-processes the map data.
312
+
313
+ This method is designed to be overridden in a subclass to perform specific
314
+ pre-processing procedures on map data. When overridden, the implementation
315
+ in the subclass must call `super().pre_process_map` first to inherit and
316
+ maintain the existing behavior of this base implementation.
317
+
318
+ :return: None
319
+ """
126
320
  # this is to be implemented at the subclass level
127
321
  # call super().pre_process_map first to inherit the following behaviour
128
322
  ...
129
323
 
130
324
 
131
325
  def _post_process_map(self):
326
+ """
327
+ Performs post-processing tasks on the map object to enhance its functionality
328
+ and ensure required adjustments or attributes are attached to it. This method
329
+ is mainly used internally to finalize map setup based on current configurations.
330
+
331
+ :raises AttributeError: This error is raised if one of the required attributes
332
+ is not properly initialized or missing during the processing.
333
+ :raises ValueError: This error is raised if provided bounds are invalid or
334
+ incompatible for fitting.
335
+ """
132
336
  self._attach_supported_tiles()
133
337
  self.add_tile_layer()
134
338
  self._add_fullscreen()
@@ -138,26 +342,76 @@ class BaseOsmMap:
138
342
 
139
343
 
140
344
  def add_tile_layer(self):
345
+ """
346
+ Adds a tile layer to the OpenStreetMap (OSM) representation.
347
+ This method is intended to handle the inclusion of additional
348
+ tile layers in the map. Subclasses should override this method,
349
+ call their custom logic, and conclude with a call to this base
350
+ implementation to add necessary controls to the map instance.
351
+
352
+ :rtype: None
353
+ :return: This method does not return any value.
354
+ """
141
355
  # Override in subclass and call super().add_tile_layer at the end
142
356
  folium.LayerControl().add_to(self.osm_map)
143
357
 
144
358
 
145
359
  def _add_fullscreen(self):
360
+ """
361
+ Adds a fullscreen functionality to the map if the fullscreen attribute is set.
362
+
363
+ This method checks whether the fullscreen mode is enabled by evaluating
364
+ the `fullscreen` attribute of the class. If `fullscreen` is set to True,
365
+ a Fullscreen instance is created with the specified position from
366
+ `fullscreen_position` and added to the map (`osm_map`).
367
+
368
+ :return: None
369
+ """
146
370
  if self.fullscreen:
147
371
  Fullscreen(position=self.fullscreen_position).add_to(self.osm_map)
148
372
 
149
373
 
150
374
  def _add_map_title(self):
375
+ """
376
+ Adds a title to the map if the title is specified.
377
+
378
+ This method checks if the attribute `map_html_title` is set. If it is,
379
+ it creates an HTML element containing the title and adds it to the
380
+ map's root HTML structure using Folium's API.
381
+
382
+ :raises AttributeError: If `osm_map` or `osm_map.get_root()` is not defined
383
+ or does not support the necessary operations.
384
+ """
151
385
  if self.map_html_title:
152
386
  self.osm_map.get_root().html.add_child(folium.Element(self.map_html_title))
153
387
 
154
388
 
155
389
  @staticmethod
156
390
  def _sanitize_html(input_html):
391
+ """
392
+ Sanitizes the provided HTML input by escaping special HTML characters.
393
+ This method ensures the input string is safe for use in HTML contexts
394
+ by converting characters like `<`, `>`, and `&` into their corresponding
395
+ HTML-safe representations.
396
+
397
+ :param input_html: The HTML string that needs to be sanitized.
398
+ :type input_html: str
399
+ :return: The sanitized version of the input HTML string with special
400
+ characters escaped.
401
+ :rtype: str
402
+ """
157
403
  return html.escape(input_html)
158
404
 
159
405
 
160
406
  def generate_map(self):
407
+ """
408
+ Generates a map by executing preprocessing, main processing, and
409
+ post-processing tasks sequentially. This method combines multiple
410
+ stages to prepare and retrieve the final map object.
411
+
412
+ :return: The completed and processed OpenStreetMap map instance
413
+ :rtype: object
414
+ """
161
415
  self.pre_process_map()
162
416
  self.process_map()
163
417
  self._post_process_map()