Files
2025-12-09 12:13:01 +01:00

258 lines
8.6 KiB
Python

from typing import Any, Dict, List, Optional
from bs4 import Tag
from pydantic import BaseModel
from rich.columns import Columns
from rich.console import Group
from rich.panel import Panel
from rich.table import Table
from rich.text import Text
from edgar.core import IntString
from edgar.richtools import repr_rich
from edgar.xmltools import child_text, child_value
__all__ = [
'Address',
'Issuer',
'Person',
'Name',
'Filer',
'get_addresses_as_columns'
]
class Address(BaseModel):
street1: Optional[str] = None
street2: Optional[str] = None
city: Optional[str] = None
state_or_country: Optional[str] = None
state_or_country_description: Optional[str] = None
zipcode: Optional[str] = None
@property
def empty(self):
return not self.street1 and not self.street2 and not self.city and not self.state_or_country and not self.zipcode
@classmethod
def from_dict(cls, address_dict: Dict[str, Any]):
return Address(
street1=address_dict.get('STREET1'),
street2=address_dict.get('STREET2'),
city=address_dict.get('CITY'),
state_or_country=address_dict.get('STATE'),
zipcode=address_dict.get('ZIP')
)
def __str__(self):
if not self.street1:
return ""
address_format = "{street1}\n"
if self.street2:
address_format += "{street2}\n"
address_format += "{city}, {state_or_country} {zipcode}"
return address_format.format(
street1=self.street1,
street2=self.street2,
city=self.city,
state_or_country=self.state_or_country_description or self.state_or_country,
zipcode=self.zipcode or ""
)
def __repr__(self):
return (f'Address(street1="{self.street1 or ""}", street2="{self.street2 or ""}", city="{self.city or ""}",'
f'zipcode="{self.zipcode or ""}", state_or_country="{self.state_or_country} or "")'
)
def get_addresses_as_columns(*,
mailing_address: Optional[Address],
business_address: Optional[Address]) -> Columns:
"""
Returns a rich Columns object with mailing and business addresses
"""
addresses = []
if mailing_address and not mailing_address.empty:
addresses.append(Panel(Text(str(mailing_address)), title='\U00002709 Mailing Address', width=40))
if business_address and not business_address.empty:
addresses.append(Panel((Text(str(business_address))), title='\U0001F3E2 Business Address', width=40))
return Columns(addresses, equal=True, expand=True)
class Issuer:
"""
<primaryIssuer>
<cik>0001961089</cik>
<entityName>1685 38th REIT, L.L.C.</entityName>
<issuerAddress>
<street1>2029 CENTURY PARK EAST</street1>
<street2>SUITE 1370</street2>
<city>LOS ANGELES</city>
<stateOrCountry>CA</stateOrCountry>
<stateOrCountryDescription>CALIFORNIA</stateOrCountryDescription>
<zipCode>90067</zipCode>
</issuerAddress>
<issuerPhoneNumber>424-313-1550</issuerPhoneNumber>
<jurisdictionOfInc>DELAWARE</jurisdictionOfInc>
<issuerPreviousNameList>
<value>None</value>
</issuerPreviousNameList>
<edgarPreviousNameList>
<value>None</value>
</edgarPreviousNameList>
<entityType>Limited Liability Company</entityType>
<yearOfInc>
<withinFiveYears>true</withinFiveYears>
<value>2022</value>
</yearOfInc>
</primaryIssuer>
"""
def __init__(self,
cik: IntString,
entity_name: str,
entity_type: str,
primary_address: Address,
phone_number: str,
jurisdiction: str,
issuer_previous_names: List[str],
edgar_previous_names: List[str],
year_of_incorporation: IntString,
incorporated_within_5_years: bool):
self.cik = cik
self.entity_name: str = entity_name
self.entity_type = entity_type
self.primary_address: Address = primary_address
self.phone_number: str = phone_number
self.issuer_previous_names = issuer_previous_names
self.edgar_previous_names = edgar_previous_names
self.jurisdiction: str = jurisdiction
self.year_of_incorporation = year_of_incorporation
self.incorporated_within_5_years: bool = incorporated_within_5_years
@classmethod
def from_xml(cls, issuer_el: Tag):
# edgar previous names
edgar_previous_names_el = issuer_el.find("edgarPreviousNameList")
edgar_previous_names = [el.text
for el in edgar_previous_names_el.find_all("value")
if el.text != 'None'] if edgar_previous_names_el else []
# issuer previous names
issuer_previous_names_el = issuer_el.find("issuerPreviousNameList")
issuer_previous_names = [el.text
for el in issuer_previous_names_el.find_all("value")
if el.text != 'None'] if issuer_previous_names_el else []
year_of_inc_el = issuer_el.find("yearOfInc")
# Address
issuer_address_el = issuer_el.find("issuerAddress")
address: Address = Address(
street1=child_text(issuer_address_el, "street1"),
street2=child_text(issuer_address_el, "street2"),
city=child_text(issuer_address_el, "city"),
state_or_country=child_text(issuer_address_el, "stateOrCountry"),
state_or_country_description=child_text(issuer_address_el, "stateOrCountryDescription"),
zipcode=child_text(issuer_address_el, "zipCode")
)
return cls(
cik=child_text(issuer_el, "cik"),
entity_name=child_text(issuer_el, "entityName"),
phone_number=child_text(issuer_el, "issuerPhoneNumber"),
jurisdiction=child_text(issuer_el, "jurisdictionOfInc"),
entity_type=child_text(issuer_el, "entityType"),
edgar_previous_names=edgar_previous_names,
primary_address=address,
issuer_previous_names=issuer_previous_names,
year_of_incorporation=child_value(issuer_el, "yearOfInc"),
incorporated_within_5_years=year_of_inc_el and child_text(year_of_inc_el, "withinFiveYears") == "true"
)
def __rich__(self):
table = Table("issuer", "entity type", "incorporated")
table.add_row(self.entity_name, self.entity_type, self.year_of_incorporation)
return Group(table)
def __repr__(self):
return repr_rich(self.__rich__())
class Person:
def __init__(self,
first_name: str,
last_name: str,
address: Optional[Address] = None):
self.first_name = first_name
self.last_name = last_name
self.address: Address = address
def __str__(self):
return f"{self.first_name} {self.first_name}"
def __repr__(self):
return f"{self.first_name} {self.last_name}"
class Name:
def __init__(self,
first_name: str,
middle_name: str,
last_name: str,
suffix:Optional[str]=None):
self.first_name = first_name
self.middle_name = middle_name
self.last_name = last_name
self.suffix = suffix
@property
def full_name(self):
return f"{self.first_name}{' ' + self.middle_name or ''} {self.last_name} {self.suffix or ''}".rstrip()
def __str__(self):
return self.full_name
def __repr__(self):
return self.full_name
class Filer:
def __init__(self,
cik: str,
entity_name: str,
file_number: str
):
self.cik: str = cik
self.entity_name: str = entity_name
self.file_number: str = file_number
def __str__(self):
return f"{self.entity_name} ({self.cik})"
def __repr__(self):
return f"{self.entity_name} ({self.cik})"
class Contact:
def __init__(self,
name: str,
phone_number: str,
email: str):
self.name: str = name
self.phone_number: str = phone_number
self.email: str = email
def __str__(self):
return f"{self.name} ({self.phone_number}) {self.email}"
def __repr__(self):
return f"{self.name} ({self.phone_number}) {self.email}"