mirror of
https://github.com/PlaneQuery/OpenAirframes.git
synced 2026-09-14 01:48:55 +02:00
feat: redistribute Canadian owner addresses to match the FAA asset
- publish street, city, postal code and care-of, which the FAA asset already carries as registrant_* for 99.7% of US registrants; dropping them here left one repository with two different postures on the same class of data - take the address from the single MAIL_RECIPIENT row rather than merging across parties, since a co-owned mark lists several people in different cities Generated-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -66,8 +66,10 @@ CCARCS `ACTIVE_FLAG` does **not** mean "current owner": 1,932 currently-Register
|
||||
`I` parties, and those rows are the `MAIL_RECIPIENT`. Prefer `A` parties where a mark has any, fall
|
||||
back to all of them otherwise. Filtering on `A` alone publishes registered aircraft with no owner.
|
||||
|
||||
Owner mailing addresses (street, city, postal code, care-of) are dropped; name, type, province and
|
||||
country are published.
|
||||
Owner mailing addresses **are** published, matching the `registrant_*` address the FAA asset already
|
||||
carries — the two sources must not diverge on this. Addresses are per-party, so they come from the
|
||||
single `MAIL_RECIPIENT == "Y"` row (exactly one per mark) and are never merged across co-owners; only
|
||||
name, type, province and country are merged lists.
|
||||
|
||||
## Fork and upstream
|
||||
|
||||
|
||||
@@ -29,8 +29,10 @@ CCARCS download page, so no licence name or URL is asserted here.
|
||||
construed as constituting an endorsement by the Government of Canada of our
|
||||
product.
|
||||
|
||||
Owner mailing addresses published in the CCARCS export (street, city, postal
|
||||
code, care-of) are dropped during ingestion and are not redistributed.
|
||||
Registered-owner mailing addresses are redistributed, matching the registrant
|
||||
addresses the FAA asset already carries. Because CCARCS lists one row per party,
|
||||
the published address is that of the single designated mail recipient rather than
|
||||
a merge across co-owners.
|
||||
|
||||
|
||||
FAA — Releasable Aircraft Database
|
||||
|
||||
@@ -34,8 +34,16 @@ CARSOWNR_COLUMNS = [
|
||||
"OWNER_NAME_OLD_FORMAT", "MAIL_RECIPIENT", "TRIMMED_MARK",
|
||||
]
|
||||
|
||||
# Owner mailing addresses are dropped rather than republished; see NOTICE.
|
||||
OWNER_PII_COLUMNS = ["STREET_NAME", "STREET_NAME2", "CITY", "POSTAL_CODE", "CARE_OF"]
|
||||
# Mailing address of the single designated recipient, matching the registrant_* address
|
||||
# the FAA build already publishes. Addresses are per-party, so they are taken from the one
|
||||
# MAIL_RECIPIENT row rather than merged across co-owners.
|
||||
OWNER_ADDRESS_COLUMNS = {
|
||||
"STREET_NAME": "owner_street_1",
|
||||
"STREET_NAME2": "owner_street_2",
|
||||
"CITY": "owner_city",
|
||||
"POSTAL_CODE": "owner_postal_code",
|
||||
"CARE_OF": "owner_care_of",
|
||||
}
|
||||
|
||||
|
||||
FOOTER_RE = re.compile(r"\s*(\d+) rows selected\.\s*")
|
||||
@@ -125,6 +133,7 @@ def _merge_owners(df_ownr: pd.DataFrame) -> pd.DataFrame:
|
||||
# Registered marks carry only "I" parties, and those rows are the MAIL_RECIPIENT.
|
||||
# So prefer active parties where a mark has any, and fall back to all of them
|
||||
# rather than publishing a registered aircraft with no owner at all.
|
||||
all_parties = df_ownr
|
||||
active = df_ownr[df_ownr["ACTIVE_FLAG"].str.upper() == "A"]
|
||||
marks_with_active = set(active["TRIMMED_MARK"])
|
||||
df_ownr = pd.concat([
|
||||
@@ -154,14 +163,25 @@ def _merge_owners(df_ownr: pd.DataFrame) -> pd.DataFrame:
|
||||
# once several parties share it. Counting distinct names rather than rows keeps this
|
||||
# consistent with owner_name, which is also deduplicated.
|
||||
grouped.loc[grouped["owner_party_count"] > 1, "owner_type"] = "Co-owner"
|
||||
return grouped
|
||||
|
||||
# Taken from the unfiltered frame: the designated recipient is the designated
|
||||
# recipient even when its own party row is flagged inactive.
|
||||
recipient = (
|
||||
all_parties[all_parties["MAIL_RECIPIENT"].str.upper() == "Y"]
|
||||
.drop_duplicates(subset="TRIMMED_MARK", keep="first")
|
||||
.rename(columns=OWNER_ADDRESS_COLUMNS)
|
||||
)
|
||||
return grouped.merge(
|
||||
recipient[["TRIMMED_MARK", *OWNER_ADDRESS_COLUMNS.values()]],
|
||||
on="TRIMMED_MARK",
|
||||
how="left",
|
||||
)
|
||||
|
||||
|
||||
def convert_tc_ccarcs_to_df(zip_path: Path, date: str) -> pd.DataFrame:
|
||||
"""Build the OpenAirframes Transport Canada frame from a CCARCS zip."""
|
||||
df = _read_ccarcs_entry(zip_path, "carscurr.txt", CARSCURR_COLUMNS)
|
||||
df_ownr = _read_ccarcs_entry(zip_path, "carsownr.txt", CARSOWNR_COLUMNS)
|
||||
df_ownr = df_ownr.drop(columns=OWNER_PII_COLUMNS)
|
||||
|
||||
df = df.merge(_merge_owners(df_ownr), on="TRIMMED_MARK", how="left")
|
||||
|
||||
@@ -196,6 +216,11 @@ def convert_tc_ccarcs_to_df(zip_path: Path, date: str) -> pd.DataFrame:
|
||||
"owner_type": df["owner_type"],
|
||||
"owner_province_or_state": df["owner_province_or_state"],
|
||||
"owner_country": df["owner_country"],
|
||||
"owner_care_of": df["owner_care_of"],
|
||||
"owner_street_1": df["owner_street_1"],
|
||||
"owner_street_2": df["owner_street_2"],
|
||||
"owner_city": df["owner_city"],
|
||||
"owner_postal_code": df["owner_postal_code"],
|
||||
"issue_date": df["ISSUE_DATE"],
|
||||
"effective_date": df["EFFECTIVE_DATE"],
|
||||
"ineffective_date": df["INEFFECTIVE_DATE"],
|
||||
|
||||
Reference in New Issue
Block a user