jageocoder 2.1.7.dev2__tar.gz → 2.1.7.dev3__tar.gz

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.
Files changed (20) hide show
  1. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/PKG-INFO +1 -1
  2. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/__init__.py +1 -1
  3. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/node.py +25 -1
  4. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/remote.py +24 -0
  5. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/rtree.py +194 -97
  6. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/tree.py +50 -12
  7. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/pyproject.toml +1 -1
  8. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/LICENSE +0 -0
  9. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/README.md +0 -0
  10. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/__main__.py +0 -0
  11. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/address.py +0 -0
  12. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/aza_master.py +0 -0
  13. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/dataset.py +0 -0
  14. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/exceptions.py +0 -0
  15. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/itaiji.py +0 -0
  16. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/itaiji_dic.json +0 -0
  17. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/module.py +0 -0
  18. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/result.py +0 -0
  19. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/strlib.py +0 -0
  20. {jageocoder-2.1.7.dev2 → jageocoder-2.1.7.dev3}/jageocoder/trie.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jageocoder
3
- Version: 2.1.7.dev2
3
+ Version: 2.1.7.dev3
4
4
  Summary: A Japanese-address geocoder for Python.
5
5
  Home-page: https://github.com/t-sagara/jageocoder/
6
6
  License: The MIT License
@@ -19,7 +19,7 @@ running the following steps.
19
19
  >>> jageocoder.searchNode('<Japanese-address>')
20
20
  """
21
21
 
22
- __version__ = '2.1.7.dev2' # The package version
22
+ __version__ = '2.1.7.dev3' # The package version
23
23
  __dictionary_version__ = '20230927' # Compatible dictionary version
24
24
  __author__ = 'Takeshi Sagara <sagara@info-proto.com>'
25
25
 
@@ -70,6 +70,30 @@ class AddressNodeTable(PortableTab.BaseTable):
70
70
  node.table = self
71
71
  return node
72
72
 
73
+ def search_ids_on(
74
+ self,
75
+ attr: str,
76
+ value: str,
77
+ ) -> list:
78
+ """
79
+ Search id list from the table on the specified attribute.
80
+
81
+ Paramters
82
+ ---------
83
+ attr: str
84
+ The name of target attribute.
85
+ value: str
86
+ The target value.
87
+
88
+ Returns
89
+ -------
90
+ List[int]
91
+ List of node ids.
92
+ """
93
+ trie = self.open_trie_on(attr)
94
+ positions = trie.get(value, [])
95
+ return [p[0] for p in positions]
96
+
73
97
  def create_indexes(self) -> None:
74
98
  """
75
99
  Create TRIE index on "name" and "note" columns.
@@ -514,7 +538,7 @@ class AddressNode(object):
514
538
  """
515
539
  new_node = copy.copy(self)
516
540
  for child in self.iter_children():
517
- if child.y <= 90.0:
541
+ if child.has_valid_coordinate_values():
518
542
  new_node.x, new_node.y = child.x, child.y
519
543
  logger.debug((
520
544
  "Node {}({}) has no coordinates. "
@@ -184,6 +184,30 @@ class RemoteNodeTable(object):
184
184
 
185
185
  return nodes
186
186
 
187
+ def search_ids_on(
188
+ self,
189
+ attr: str,
190
+ value: str,
191
+ ) -> list:
192
+ """
193
+ Search id from the table on the specified attribute on the remote server.
194
+
195
+ Paramters
196
+ ---------
197
+ attr: str
198
+ The name of target attribute.
199
+ value: str
200
+ The target value.
201
+
202
+ Returns
203
+ -------
204
+ List[Record]
205
+ List of records.
206
+ """
207
+ nodes = self.search_records_on(attr, value)
208
+ ids = [node.id for node in nodes]
209
+ return ids
210
+
187
211
 
188
212
  class RemoteTree(AddressTree):
189
213
  """
@@ -1,4 +1,5 @@
1
1
  from abc import ABC
2
+ import copy
2
3
  from logging import getLogger
3
4
  import os
4
5
  from typing import Iterable, List, Optional, Tuple
@@ -15,6 +16,16 @@ from jageocoder.node import AddressNode, AddressNodeTable
15
16
  logger = getLogger(__name__)
16
17
 
17
18
 
19
+ class NodeDist(object):
20
+
21
+ def __init__(self, dist: float, node: AddressNode) -> None:
22
+ self.dist = dist
23
+ self.node = node
24
+
25
+ def __repr__(self) -> str:
26
+ return f"NodeDist({self.dist}, {self.node})"
27
+
28
+
18
29
  class DelaunayTriangle(ABC):
19
30
 
20
31
  @classmethod
@@ -131,8 +142,8 @@ class DelaunayTriangle(ABC):
131
142
  cls,
132
143
  x: float,
133
144
  y: float,
134
- nodes: List[AddressNode]
135
- ) -> List[AddressNode]:
145
+ nodes: List[NodeDist]
146
+ ) -> List[NodeDist]:
136
147
  """
137
148
  Select the 3 nodes that make the smallest triangle
138
149
  surrounding the target point.
@@ -143,13 +154,14 @@ class DelaunayTriangle(ABC):
143
154
  The longitude of the target point.
144
155
  y: float
145
156
  The latitude of the target point.
146
- nodes: List[AddressNode]
147
- The candidate nodes.
157
+ nodes: List[NodeDist]
158
+ The candidate list of (distance, node).
148
159
 
149
160
  Returns
150
161
  -------
151
- List[AddressNode]
152
- Up to 3 nodes surrounding the target point.
162
+ List[NodeDist]
163
+ Up to 3 nodes surrounding the target point
164
+ and their distance.
153
165
  """
154
166
  def kval(t: Tuple[int, int, int]) -> int:
155
167
  sval = sorted(t)
@@ -161,9 +173,9 @@ class DelaunayTriangle(ABC):
161
173
  for p2 in range(p1 + 1, len(nodes)):
162
174
  if cls.p_contained_triangle(
163
175
  (x, y),
164
- (nodes[p0].x, nodes[p0].y),
165
- (nodes[p1].x, nodes[p1].y),
166
- (nodes[p2].x, nodes[p2].y)
176
+ (nodes[p0].node.x, nodes[p0].node.y),
177
+ (nodes[p1].node.x, nodes[p1].node.y),
178
+ (nodes[p2].node.x, nodes[p2].node.y)
167
179
  ):
168
180
  triangle = [p0, p1, p2]
169
181
  break
@@ -187,10 +199,10 @@ class DelaunayTriangle(ABC):
187
199
  continue
188
200
 
189
201
  if cls.p_contained_circumcircle(
190
- (nodes[i].x, nodes[i].y),
191
- (nodes[triangle[0]].x, nodes[triangle[0]].y),
192
- (nodes[triangle[1]].x, nodes[triangle[1]].y),
193
- (nodes[triangle[2]].x, nodes[triangle[2]].y)
202
+ (nodes[i].node.x, nodes[i].node.y),
203
+ (nodes[triangle[0]].node.x, nodes[triangle[0]].node.y),
204
+ (nodes[triangle[1]].node.x, nodes[triangle[1]].node.y),
205
+ (nodes[triangle[2]].node.x, nodes[triangle[2]].node.y)
194
206
  ):
195
207
  new_triangle = None
196
208
  for j in range(3):
@@ -202,9 +214,9 @@ class DelaunayTriangle(ABC):
202
214
 
203
215
  if cls.p_contained_triangle(
204
216
  (x, y),
205
- (nodes[tt[0]].x, nodes[tt[0]].y),
206
- (nodes[tt[1]].x, nodes[tt[1]].y),
207
- (nodes[tt[2]].x, nodes[tt[2]].y)
217
+ (nodes[tt[0]].node.x, nodes[tt[0]].node.y),
218
+ (nodes[tt[1]].node.x, nodes[tt[1]].node.y),
219
+ (nodes[tt[2]].node.x, nodes[tt[2]].node.y)
208
220
  ):
209
221
  new_triangle = tt
210
222
  break
@@ -309,6 +321,8 @@ class Index(object):
309
321
  node_table: AddressNodeTable = self._tree.address_nodes
310
322
 
311
323
  max_id = node_table.count_records()
324
+
325
+ logger.info("Building RTree for reverse geocoding...")
312
326
  id = AddressNode.ROOT_NODE_ID
313
327
  with tqdm(total=max_id, mininterval=0.5, ascii=True) as pbar:
314
328
  prev_id = 0
@@ -317,22 +331,19 @@ class Index(object):
317
331
  prev_id = id
318
332
 
319
333
  node = node_table.get_record(pos=id)
320
- if node.level > AddressLevel.AZA:
321
- id = node.sibling_id
322
- continue
323
- elif node.level < AddressLevel.OAZA:
334
+ if node.level <= AddressLevel.WARD or node.level > AddressLevel.BLOCK:
324
335
  id += 1
325
336
  continue
326
- elif not node.has_valid_coordinate_values():
337
+
338
+ if not node.has_valid_coordinate_values():
327
339
  node = node.add_dummy_coordinates()
328
- if not node.has_valid_coordinate_values():
329
- id += 1
330
- continue
331
340
 
332
- file_idx.insert(
333
- id=id,
334
- coordinates=(node.x, node.y, node.x, node.y)
335
- )
341
+ if node.has_valid_coordinate_values():
342
+ file_idx.insert(
343
+ id=id,
344
+ coordinates=(node.x, node.y, node.x, node.y),
345
+ )
346
+
336
347
  id += 1
337
348
 
338
349
  return file_idx
@@ -366,20 +377,29 @@ class Index(object):
366
377
  """
367
378
  node_table = self._tree.address_nodes
368
379
  node = node_table.get_record(pos=node_table.count_records() // 2)
369
- while node.level < AddressLevel.OAZA:
370
- node = node_table.get_record(pos=node.id + 1)
371
380
 
372
- while node.level > AddressLevel.AZA:
373
- node = node.parent
381
+ while True:
382
+ while node.level < AddressLevel.BLOCK:
383
+ node = node_table.get_record(pos=node.id + 1)
384
+
385
+ while node.level > AddressLevel.BLOCK:
386
+ node = node.parent
387
+
388
+ if node.has_valid_coordinate_values():
389
+ break
390
+
391
+ node = node_table.get_record(pos=node.sibling_id)
374
392
 
375
- return node.id in self.idx.nearest((node.x, node.y, node.x, node.y), 2)
393
+ results = tuple(self.idx.nearest((node.x, node.y, node.x, node.y), 20))
394
+ return len(results) > 0 and node.id in results
376
395
 
377
396
  def _sort_by_dist(
378
397
  self,
379
398
  lon: float,
380
399
  lat: float,
381
- id_list: Iterable[int]
382
- ) -> List[AddressNode]:
400
+ id_list: Iterable[int],
401
+ node_map: Optional[dict] = None,
402
+ ) -> Tuple[List[NodeDist], dict]:
383
403
  """
384
404
  Sort nodes by real(projected) distance from the target point.
385
405
 
@@ -394,17 +414,26 @@ class Index(object):
394
414
 
395
415
  Returns
396
416
  -------
397
- List[AddressNode]
398
- The sorted list of address nodes.
417
+ Tuple[List[NodeDist], dict]
418
+ The sorted list of (distance, address node) and a node map.
399
419
  """
420
+ node_map = node_map or {}
400
421
  results = []
401
- for node_id in id_list:
402
- node = self._tree.get_address_node(id=node_id)
403
- dist = self.distance(node.x, node.y, lon, lat)
404
- results.append((node, dist))
422
+ for node_id in set(id_list):
423
+ node = self._tree.get_node_by_id(node_id=node_id)
424
+ if not node.has_valid_coordinate_values():
425
+ node = node.add_dummy_coordinates()
405
426
 
406
- results.sort(key=lambda x: x[1])
407
- return [x[0] for x in results]
427
+ key = (node.x, node.y)
428
+ if key in node_map:
429
+ node_map[key].append(node)
430
+ else:
431
+ node_map[key] = [node]
432
+ dist = self.distance(node.x, node.y, lon, lat)
433
+ results.append(NodeDist(dist, node))
434
+
435
+ results.sort(key=lambda x: x.dist)
436
+ return (results, node_map)
408
437
 
409
438
  def nearest(
410
439
  self,
@@ -434,95 +463,163 @@ class Index(object):
434
463
  [{"candidate":AddressNode or dict, "dist":float}]
435
464
  Returns the results of retrieval up to 3 nodes.
436
465
  """
437
- level = level or AddressLevel.AZA
438
-
439
- # Search nodes by Rtree Index
440
- nodes = []
441
- ancestors = set()
442
- max_level = 0
443
- for node in self._sort_by_dist(x, y, self.idx.nearest((x, y, x, y), 10)):
444
- if node.id in ancestors:
445
- continue
446
-
447
- if not node.has_valid_coordinate_values():
448
- node = node.add_dummy_coordinates()
449
466
 
450
- nodes.append(node)
451
- max_level = max(max_level, node.level)
452
- # Ancestor nodes of registering node are excluded.
453
- cur = node.parent
454
- while cur is not None:
455
- nodes = [node for node in nodes if node.id != cur.id]
456
- ancestors.add(cur.id)
457
- cur = cur.parent
458
-
459
- if level > max_level:
460
- # Search points in the higher levels
461
- local_idx = index.Rtree() # Create local rtree on memory
462
- for node in nodes:
463
- child_id = node.id
464
- while child_id < node.sibling_id:
465
- child_node = self._tree.get_address_node(id=child_id)
466
- if child_node.level > level:
467
- child_id = child_node.parent.sibling_id
468
- continue
469
- elif not child_node.has_valid_coordinate_values():
470
- child_node = child_node.add_dummy_coordinates()
471
- if not child_node.has_valid_coordinate_values():
472
- child_id += 1
473
- continue
474
-
475
- local_idx.insert(
476
- id=child_id,
477
- coordinates=(
478
- child_node.x, child_node.y,
479
- child_node.x, child_node.y))
480
- child_id += 1
467
+ def _remove_parent_nodes(
468
+ candidates: Iterable[NodeDist]
469
+ ) -> List[NodeDist]:
470
+ ancestors = set()
471
+ max_level = 0
472
+ if len(candidates) == 0:
473
+ return []
481
474
 
482
475
  nodes = []
483
- ancestors = set()
484
- for node in self._sort_by_dist(x, y, local_idx.nearest((x, y, x, y), 20)):
476
+ for v in candidates:
477
+ dist, node = v.dist, v.node
485
478
  if node.id in ancestors:
486
479
  continue
487
480
 
488
481
  if not node.has_valid_coordinate_values():
489
482
  node = node.add_dummy_coordinates()
490
483
 
491
- nodes.append(node)
492
- # Ancestor nodes of registering node are excluded.
484
+ nodes.append(NodeDist(dist, node))
485
+ max_level = max(max_level, node.level)
486
+
487
+ # List ancestor nodes of registering node.
493
488
  cur = node.parent
494
489
  while cur is not None:
495
- nodes = [node for node in nodes if node.id != cur.id]
490
+ # nodes = [node for node in nodes if node.id != cur.id]
496
491
  ancestors.add(cur.id)
497
492
  cur = cur.parent
498
493
 
494
+ # Exclude ancestor nodes
495
+ nodes = [node for node in nodes if node.node.id not in ancestors]
496
+ return nodes
497
+
498
+ def _get_k_nearest_child_nodes(
499
+ aza_node_dists: List[NodeDist],
500
+ *,
501
+ candidates: Optional[List[NodeDist]] = None,
502
+ node_map: Optional[dict] = None,
503
+ k: Optional[int] = 20,
504
+ min_k: Optional[int] = 0,
505
+ max_dist: Optional[float] = 500.0,
506
+ ) -> Tuple[List[NodeDist], dict]:
507
+ candidates = candidates or []
508
+ node_map = node_map or {}
509
+ for v in aza_node_dists:
510
+ dist, node = v.dist, v.node
511
+ child_id = node.id + 1
512
+ for child_id in range(node.id + 1, node.sibling_id):
513
+ child_node = self._tree.get_node_by_id(
514
+ node_id=child_id)
515
+ if child_node.level > level:
516
+ continue
517
+
518
+ if not child_node.has_valid_coordinate_values():
519
+ if child_node.level == level:
520
+ continue
521
+
522
+ child_node = child_node.add_dummy_coordinates()
523
+ if not child_node.has_valid_coordinate_values():
524
+ continue
525
+
526
+ key = (child_node.x, child_node.y)
527
+ if key in node_map:
528
+ # A node with the same coordinates are already registered
529
+ node_map[key].append(child_node)
530
+ continue
531
+
532
+ dist = self.distance(x, y, child_node.x, child_node.y)
533
+ i = len(candidates)
534
+ while i > 0:
535
+ if dist >= candidates[i - 1].dist:
536
+ break
537
+
538
+ i -= 1
539
+
540
+ if i < min_k or (i < k and dist <= max_dist):
541
+ candidates.insert(i, NodeDist(dist, child_node))
542
+ node_map[key] = [child_node]
543
+ n = len(candidates)
544
+ if n > k:
545
+ delnode = candidates[k].node
546
+ del candidates[k]
547
+ delkey = (delnode.x, delnode.y)
548
+ node_map[delkey].remove(delnode)
549
+ if len(node_map[delkey]) == 0:
550
+ del node_map[delkey]
551
+
552
+ elif n > min_k and candidates[min_k].dist > max_dist:
553
+ delnode = candidates[min_k].node
554
+ del candidates[min_k]
555
+ delkey = (delnode.x, delnode.y)
556
+ node_map[delkey].remove(delnode)
557
+ if len(node_map[delkey]) == 0:
558
+ del node_map[delkey]
559
+
560
+ return (candidates, node_map)
561
+
562
+ level = level or AddressLevel.AZA
563
+
564
+ # Retrieve top k-nearest nodes using the R-tree index.
565
+ nearests = self.idx.nearest((x, y, x, y), 20)
566
+ node_dists, node_map = self._sort_by_dist(x, y, nearests)
567
+ node_dists = _remove_parent_nodes(node_dists)
568
+
569
+ if level > AddressLevel.BLOCK:
570
+ candidates, node_map = _get_k_nearest_child_nodes(
571
+ node_dists,
572
+ candidates=copy.copy(node_dists),
573
+ node_map=node_map,
574
+ min_k=1)
575
+
576
+ node_dists = _remove_parent_nodes(candidates)
577
+
499
578
  # Select the 3 nodes that make the smallest triangle
500
579
  # surrounding the target point
501
- if len(nodes) == 0:
580
+ if len(node_dists) == 0:
502
581
  return []
503
582
 
504
- if self.distance(x, y, nodes[0].x, nodes[0].y) < 1.0e-02:
583
+ if len(node_dists) <= 3 or node_dists[0].dist < 1.0e-02:
505
584
  # If the distance between the nearest point and the search point is
506
585
  # less than 1 cm, it returns three points in order of distance.
507
586
  # This is because the nearest point may not be included in
508
587
  # the search results due to a calculation error.
509
- nodes = nodes[0:3]
588
+ node_dists = node_dists[0:3]
510
589
  else:
511
- nodes = DelaunayTriangle.select(x, y, nodes)
590
+ node_dists = DelaunayTriangle.select(x, y, node_dists)
591
+
592
+ # Restore nodes with the same coordinates
593
+ if node_map is not None:
594
+ _node_dists = []
595
+ for v in node_dists:
596
+ dist, node = v.dist, v.node
597
+ key = (node.x, node.y)
598
+ for n in node_map[key]:
599
+ _node_dists.append(NodeDist(dist, n))
600
+
601
+ node_dists = _node_dists
512
602
 
513
603
  # Convert nodes to the dict format.
514
604
  results = []
515
605
  registered = set()
516
- for node in nodes:
606
+ for v in node_dists:
607
+ dist, node = v.dist, v.node
517
608
  while node.level > level:
518
609
  node = node.parent
610
+ dist = None
611
+ if not node.has_valid_coordinate_values():
612
+ node.x, node.y = v.node.x, v.node.y
519
613
 
520
614
  if node.id in registered:
521
615
  continue
522
616
 
617
+ if dist is None:
618
+ dist = self.distance(x, y, node.x, node.y)
619
+
523
620
  results.append({
524
621
  "candidate": node.as_dict() if as_dict else node,
525
- "dist": self.distance(x, y, node.x, node.y)
622
+ "dist": dist
526
623
  })
527
624
  registered.add(node.id)
528
625
 
@@ -1,17 +1,14 @@
1
1
  from collections import OrderedDict
2
- import csv
3
- import json
4
2
  from logging import getLogger
5
3
  import os
6
4
  from pathlib import Path
7
5
  import re
8
6
  import site
9
7
  import sys
10
- from typing import Any, Union, List, Set, NoReturn, Optional, TextIO
8
+ from typing import Any, Union, List, Set, Optional
11
9
 
12
10
  from deprecated import deprecated
13
11
 
14
- import jageocoder
15
12
  from jageocoder.address import AddressLevel
16
13
  from jageocoder.aza_master import AzaMaster
17
14
  from jageocoder.exceptions import AddressTreeException
@@ -285,11 +282,13 @@ class AddressTree(object):
285
282
  node_id: int
286
283
  The target node id.
287
284
 
288
- Return
289
- ------
285
+ Returns
286
+ -------
290
287
  AddressNode
291
288
  """
292
- return self.address_nodes.get_record(node_id)
289
+ node = self.address_nodes.get_record(node_id)
290
+ node.tree = self
291
+ return node
293
292
 
294
293
  def search_nodes_by_codes(
295
294
  self,
@@ -316,6 +315,31 @@ class AddressTree(object):
316
315
 
317
316
  return nodes
318
317
 
318
+ def search_ids_by_codes(
319
+ self,
320
+ category: str,
321
+ value: str) -> List[AddressNode]:
322
+ """
323
+ Search node ids by category and value.
324
+
325
+ Parameters
326
+ ----------
327
+ category: str
328
+ Category name such as 'jisx0402' or 'postcode'.
329
+ value: str
330
+ Target value.
331
+
332
+ Returns
333
+ -------
334
+ List[int]
335
+ """
336
+ ids = []
337
+ pattern = '{}:{}'.format(category, value)
338
+ ids = self.address_nodes.search_ids_on(
339
+ attr="note", value=pattern) # exact match
340
+
341
+ return ids
342
+
319
343
  @deprecated("Use 'node.get_fullname()' instead of this method.")
320
344
  def get_node_fullname(self, node: Union[AddressNode, int]) -> List[str]:
321
345
  if isinstance(node, int):
@@ -965,6 +989,7 @@ class AddressTree(object):
965
989
 
966
990
  return results
967
991
 
992
+ @deprecated(reason="Use 'get_node_by_id'.", version="2.1.7")
968
993
  def get_address_node(self, id: int) -> AddressNode:
969
994
  """
970
995
  Get address node from the tree by its id.
@@ -1171,17 +1196,30 @@ class AddressTree(object):
1171
1196
  """
1172
1197
  if len(id) == 12:
1173
1198
  # jisx0402(5digits) + aza_id(7digits)
1174
- candidates = self.search_nodes_by_codes(
1199
+ citynode = self.search_by_citycode(code=id[0:5])
1200
+ if len(citynode) == 0:
1201
+ return []
1202
+
1203
+ citynode = citynode[0]
1204
+ candidates = self.search_ids_by_codes(
1175
1205
  category="aza_id",
1176
1206
  value=id[-7:])
1177
- nodes = [x for x in candidates if x.get_city_jiscode() == id[0:5]]
1207
+ nodes = [self.address_nodes.get_record(x)
1208
+ for x in candidates
1209
+ if x >= citynode.id and x < citynode.sibling_id]
1178
1210
  elif len(id) == 13:
1179
1211
  # lasdec(6digits) + aza_id(7digits)
1180
- candidates = self.search_nodes_by_codes(
1212
+ citynode = self.search_by_citycode(code=id[0:6])
1213
+ if len(citynode) == 0:
1214
+ return []
1215
+
1216
+ citynode = citynode[0]
1217
+ candidates = self.search_ids_by_codes(
1181
1218
  category="aza_id",
1182
1219
  value=id[-7:])
1183
- nodes = [x for x in candidates
1184
- if x.get_city_local_authority_code() == id[0:6]]
1220
+ nodes = [self.address_nodes.get_record(x)
1221
+ for x in candidates
1222
+ if x >= citynode.id and x < citynode.sibling_id]
1185
1223
  else:
1186
1224
  nodes = self.search_nodes_by_codes(
1187
1225
  category="aza_id",
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "jageocoder"
3
- version = "2.1.7.dev2"
3
+ version = "2.1.7.dev3"
4
4
  description = "A Japanese-address geocoder for Python."
5
5
  authors = ["Takeshi Sagara <sagara@info-proto.com>"]
6
6
  repository = "https://github.com/t-sagara/jageocoder/"
File without changes