Skip to content
This repository has been archived by the owner on Apr 9, 2019. It is now read-only.

Commit

Permalink
Correct successors/ancestors for fusion+split, fix #43
Browse files Browse the repository at this point in the history
  • Loading branch information
davidbgk committed May 19, 2017
1 parent 75a4840 commit b5cb961
Show file tree
Hide file tree
Showing 11 changed files with 623 additions and 540 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# CHANGELOG

## 8.1.1 — 2017-05-12
## 8.1.3 — 2017-05-18

* Correct successors/ancestors in case of fusions then splits.

## 8.1.2 — 2017-05-12

* Add 2-letters ISO codes for overseas collectivities.

Expand Down
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,3 @@ Note that the duration of the whole test suite run is about 5 minutes.
That's why you would probably prefer to run a particular test:

$ python -m pytest tests/test_actions.py::test_change_name



## TODO

* Collect feedback from reusers
384 changes: 192 additions & 192 deletions exports/communes/communes.csv

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion exports/communes/communes_1962-03-07.csv
Original file line number Diff line number Diff line change
Expand Up @@ -21422,7 +21422,7 @@ COM55150@1942-01-01,55150,1942-01-01 00:00:00,9999-12-31 23:59:59,Demange-aux-Ea
COM55151@1942-01-01,55151,1942-01-01 00:00:00,1972-12-31 23:59:59,Deuxnouds-aux-Bois,COM55274@1942-01-01,,DEP55@1860-07-01,NULL,330
COM55152@1942-01-01,55152,1942-01-01 00:00:00,1972-12-31 23:59:59,Deuxnouds-devant-Beauzée,COM55040@1973-01-01,,DEP55@1860-07-01,NULL,330
COM55153@1942-01-01,55153,1942-01-01 00:00:00,9999-12-31 23:59:59,Dieppe-sous-Douaumont,,,DEP55@1860-07-01,183,0
COM55154@1942-01-01,55154,1942-01-01 00:00:00,1984-12-31 23:59:59,Dieue,COM55154@1985-01-01,COM55204@1942-01-01,DEP55@1860-07-01,262,120
COM55154@1942-01-01,55154,1942-01-01 00:00:00,1984-12-31 23:59:59,Dieue,COM55154@1985-01-01;COM55204@1985-01-01,COM55204@1942-01-01,DEP55@1860-07-01,262,120
COM55155@1942-01-01,55155,1942-01-01 00:00:00,9999-12-31 23:59:59,Dombasle-en-Argonne,,,DEP55@1860-07-01,432,0
COM55156@1942-01-01,55156,1942-01-01 00:00:00,9999-12-31 23:59:59,Dombras,,,DEP55@1860-07-01,132,0
COM55157@1942-01-01,55157,1942-01-01 00:00:00,9999-12-31 23:59:59,Dommartin-la-Montagne,,,DEP55@1860-07-01,60,0
Expand Down
224 changes: 112 additions & 112 deletions exports/communes/communes_2000-01-01.csv

Large diffs are not rendered by default.

220 changes: 110 additions & 110 deletions exports/communes/communes_2016-01-01.csv

Large diffs are not rendered by default.

218 changes: 109 additions & 109 deletions exports/communes/communes_2017-01-01.csv

Large diffs are not rendered by default.

65 changes: 60 additions & 5 deletions geohisto/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def creation_delegated(towns, record):
towns.delete(current_town)


@in_case_of(CHANGE_NAME_REINSTATEMENT, REINSTATEMENT)
@in_case_of(REINSTATEMENT)
def reinstatement(towns, record):
current_town = towns.get_current(record.depcom, record.eff)

Expand All @@ -134,13 +134,43 @@ def reinstatement(towns, record):
towns.upsert(new_town)

old_town = current_town.generate(
nccenr=record.nccanc or record.nccoff,
nccenr=record.nccoff,
end_datetime=min(current_town.end_datetime, record.eff - DELTA),
modification=record.mod
)
if new_town.valid_at(old_town.end_datetime + DELTA):
old_town = old_town.add_successor(new_town.id)
towns.upsert(old_town)
towns.replace_successor(old_town, new_town,
valid_datetime=new_town.start_datetime - DELTA)


@in_case_of(CHANGE_NAME_REINSTATEMENT)
def change_name_reinstatement(towns, record):
current_town = towns.get_current(record.depcom, record.eff)
new_town = current_town.generate(
id=compute_id(current_town.depcom, record.effdate),
start_datetime=record.eff,
end_datetime=END_DATETIME,
nccenr=record.nccoff,
successors='',
modification=0
)
towns.upsert(new_town)

old_town = current_town.generate(
nccenr=record.nccanc or record.nccoff,
end_datetime=min(current_town.end_datetime, record.eff - DELTA),
modification=record.mod
)
old_town = old_town.add_successor(new_town.id)
for ancestor in old_town.get_ancestors(towns):
for guessed_successor in towns.valid_at(
old_town.end_datetime + DELTA, depcom=ancestor.depcom):
if (guessed_successor and guessed_successor.id != old_town.id and
guessed_successor.id != new_town.id):
old_town = old_town.add_successor(guessed_successor.id)
towns.upsert(old_town)


@in_case_of(SPLITING)
Expand All @@ -153,16 +183,34 @@ def spliting(towns, record):
towns.upsert(current_town)


@in_case_of(DELETION_PARTITION, DELETION_FUSION,
FUSION_ASSOCIATION_ASSOCIATED, CREATION_DELEGATED)
@in_case_of(DELETION_PARTITION, DELETION_FUSION, CREATION_DELEGATED)
def deletion(towns, record):
current_town = towns.get_current(record.depcom, record.eff)
old_town = current_town.generate(
nccenr=record.nccoff,
end_datetime=record.eff - DELTA,
modification=record.mod
)
successor = towns.get_current(record.comech, record.eff)
old_town = old_town.add_successor(successor.id)
towns.upsert(old_town)


@in_case_of(FUSION_ASSOCIATION_ASSOCIATED)
def fusion_association_associated(towns, record):
current_town = towns.get_current(record.depcom, record.eff)

end_datetime = record.eff - DELTA

# It happens with `Lamarche-en-Woëvre` for instance
# TODO: move to specials.
# It happens only with `Lamarche-en-Woëvre` for instance
# because the reinstatement is at the same date of the (re)fusion,
# so we set the end_date just after the start_date exceptionnally.
# Record(depcom='55273', mod=330, eff=datetime.datetime(1983, 1, 1, 0, 0),
# nccoff='Lamarche-en-Woëvre', nccanc='', comech='55386', dep='55',
# com='273', depanc='', last=None, effdate=datetime.date(1983, 1, 1))
# Current town: <Town (COM55273@1983-01-01): Lamarche-en-Woëvre
# from 1983-01-01 to 9999-12-31 with successors and mod 0>
has_temporary_existence = current_town.start_datetime == record.eff
if has_temporary_existence:
end_datetime = record.eff + DELTA
Expand All @@ -174,6 +222,13 @@ def deletion(towns, record):
)
successor = towns.get_current(record.comech, record.eff)
old_town = old_town.add_successor(successor.id)
if successor.modification == CHANGE_NAME_REINSTATEMENT:
# Deal with fusions then splits declared in the wrong order.
if old_town.depcom not in successor.successors:
new_town = towns.get_current(
old_town.depcom, successor.end_datetime + DELTA)
successor = successor.add_successor(new_town.id)
towns.upsert(successor)
towns.upsert(old_town)


Expand Down
14 changes: 14 additions & 0 deletions geohisto/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ def add_ancestor(self, ancestor):
ancestor = self.ancestors + ';' + ancestor
return self._replace(**{'ancestors': ancestor})

def get_ancestors(self, towns):
"""Iterator across ancestors of the current town."""
for town in towns.with_successors():
for successor_id in town.successors.split(';'):
if successor_id == self.id:
yield town

def add_successor(self, successor):
"""Append the given successor to the current list if any."""
if self.successors:
Expand All @@ -192,6 +199,13 @@ def replace_successor(self, old_successor, new_successor):
successors = self.successors.replace(old_successor, new_successor)
return self._replace(**{'successors': successors.strip(';')})

def remove_successor(self, successor):
"""Remove the given successor from the current list."""
successors = ';'.join([
succ for succ in self.successors.split(';')
if succ != successor])
return self._replace(**{'successors': successors})

def clear_successors(self):
"""Remove all successors."""
return self._replace(**{'successors': ''})
Expand Down
10 changes: 8 additions & 2 deletions geohisto/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,13 @@ def compute_ancestors(towns):
for successor_id in town.successors.split(';'):
successor = towns.retrieve(successor_id)
if successor:
successor = successor.add_ancestor(town.id)
towns.upsert(successor)
# Avoid weird parenthood relations.
if (town.id not in town.successors and
town.end_datetime <= successor.end_datetime):
successor = successor.add_ancestor(town.id)
towns.upsert(successor)
else:
town = town.remove_successor(successor.id)
towns.upsert(town)
else:
print('Successor not found for', town.repr_insee)
14 changes: 12 additions & 2 deletions tests/test_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,24 @@ def test_change_name_reinstatement_after_fusion():
dep='28', com='159', mod=SPLITING,
effdate=date(1987, 1, 1),
nccoff='Framboisière', comech='28368')
fusion_association_associated = record_factory(
dep='28', com='368', mod=FUSION_ASSOCIATION_ASSOCIATED,
effdate=date(1972, 12, 22), comech='28159',
nccoff='Saucelle')
reinstatement_record = record_factory(
dep='28', com='368', mod=REINSTATEMENT,
effdate=date(1987, 1, 1), comech='28159',
nccoff='Saucelle', nccanc='Framboisière-la-Saucelle')
history = [
change_name_fusion_record, change_name_reinstatement_record,
spliting_record
spliting_record, fusion_association_associated, reinstatement_record
]
compute(towns, history)
framb, framb_saucelle, framb2 = towns.filter(depcom='28159')
saucelle, saucelle2 = towns.filter(depcom='28368')
assert saucelle.successors == framb_saucelle.id
assert framb_saucelle.id == 'COM28159@1972-12-22'
assert framb_saucelle.successors == framb2.id
assert framb_saucelle.successors == framb2.id + ';' + saucelle2.id
assert framb_saucelle.modification == CHANGE_NAME_REINSTATEMENT
assert framb.id == 'COM28159@1942-01-01'
assert framb.successors == framb_saucelle.id
Expand Down

0 comments on commit b5cb961

Please sign in to comment.