|
6 | 6 |
|
7 | 7 | from .enhanced_data_table import EnhancedTableCell |
8 | 8 | from .enums import Justify |
9 | | -from .formatting import as_compact, as_float, as_percent |
| 9 | +from .formatting import ( |
| 10 | + as_bool, |
| 11 | + as_compact, |
| 12 | + as_date, |
| 13 | + as_datetime, |
| 14 | + as_enum, |
| 15 | + as_float, |
| 16 | + as_percent, |
| 17 | +) |
10 | 18 | from .quote_table import quote_column |
11 | 19 |
|
12 | 20 | if TYPE_CHECKING: |
| 21 | + from datetime import date, datetime |
| 22 | + from enum import Enum |
| 23 | + |
13 | 24 | from .quote_table import QuoteColumn |
14 | 25 |
|
15 | 26 |
|
@@ -184,6 +195,127 @@ def __init__( |
184 | 195 | ) |
185 | 196 |
|
186 | 197 |
|
| 198 | +class DateCell(EnhancedTableCell): |
| 199 | + """Cell that renders date values.""" |
| 200 | + |
| 201 | + def __init__( |
| 202 | + self, |
| 203 | + value: date | None, |
| 204 | + *, |
| 205 | + date_format: str | None = None, |
| 206 | + justification: Justify = Justify.LEFT, |
| 207 | + style: str = "", |
| 208 | + secondary_key: str | None = None, |
| 209 | + ) -> None: |
| 210 | + """Initialize the date cell. |
| 211 | +
|
| 212 | + Args: |
| 213 | + value (date | None): The date value to display. |
| 214 | + date_format (str | None): Optional format override for display. |
| 215 | + justification (Justify): The text justification. |
| 216 | + style (str): The style string for the cell. |
| 217 | + secondary_key (str | None): An optional secondary string key to use for |
| 218 | + tie-breaking during sorting. |
| 219 | + """ |
| 220 | + |
| 221 | + safe_value = float("-inf") if value is None else value.toordinal() |
| 222 | + super().__init__( |
| 223 | + _with_secondary_key(safe_value, secondary_key), |
| 224 | + as_date(value, date_format), |
| 225 | + justification, |
| 226 | + style, |
| 227 | + ) |
| 228 | + |
| 229 | + |
| 230 | +class DateTimeCell(EnhancedTableCell): |
| 231 | + """Cell that renders datetime values.""" |
| 232 | + |
| 233 | + def __init__( |
| 234 | + self, |
| 235 | + value: datetime | None, |
| 236 | + *, |
| 237 | + datetime_format: str | None = None, |
| 238 | + justification: Justify = Justify.LEFT, |
| 239 | + style: str = "", |
| 240 | + secondary_key: str | None = None, |
| 241 | + ) -> None: |
| 242 | + """Initialize the datetime cell. |
| 243 | +
|
| 244 | + Args: |
| 245 | + value (datetime | None): The datetime value to display. |
| 246 | + datetime_format (str | None): Optional format override for display. |
| 247 | + justification (Justify): The text justification. |
| 248 | + style (str): The style string for the cell. |
| 249 | + secondary_key (str | None): An optional secondary string key to use for |
| 250 | + tie-breaking during sorting. |
| 251 | + """ |
| 252 | + |
| 253 | + safe_value = float("-inf") if value is None else value.timestamp() |
| 254 | + super().__init__( |
| 255 | + _with_secondary_key(safe_value, secondary_key), |
| 256 | + as_datetime(value, datetime_format), |
| 257 | + justification, |
| 258 | + style, |
| 259 | + ) |
| 260 | + |
| 261 | + |
| 262 | +class EnumCell(EnhancedTableCell): |
| 263 | + """Cell that renders enum values in title case.""" |
| 264 | + |
| 265 | + def __init__( |
| 266 | + self, |
| 267 | + value: Enum | None, |
| 268 | + *, |
| 269 | + justification: Justify = Justify.LEFT, |
| 270 | + style: str = "", |
| 271 | + secondary_key: str | None = None, |
| 272 | + ) -> None: |
| 273 | + """Initialize the enum cell. |
| 274 | +
|
| 275 | + Args: |
| 276 | + value (Enum | None): The enum value to display. |
| 277 | + justification (Justify): The text justification. |
| 278 | + style (str): The style string for the cell. |
| 279 | + secondary_key (str | None): An optional secondary string key to use for |
| 280 | + tie-breaking during sorting. |
| 281 | + """ |
| 282 | + |
| 283 | + display_value = as_enum(value) |
| 284 | + primary = display_value.lower() if value is not None else "" |
| 285 | + sort_key = (primary, secondary_key.lower()) if secondary_key else (primary,) |
| 286 | + super().__init__(sort_key, display_value, justification, style) |
| 287 | + |
| 288 | + |
| 289 | +class BooleanCell(EnhancedTableCell): |
| 290 | + """Cell that renders boolean values as checkboxes.""" |
| 291 | + |
| 292 | + def __init__( |
| 293 | + self, |
| 294 | + *, |
| 295 | + value: bool | None, |
| 296 | + justification: Justify = Justify.CENTER, |
| 297 | + style: str = "", |
| 298 | + secondary_key: str | None = None, |
| 299 | + ) -> None: |
| 300 | + """Initialize the boolean cell. |
| 301 | +
|
| 302 | + Args: |
| 303 | + value (bool | None): The boolean value to display. |
| 304 | + justification (Justify): The text justification. |
| 305 | + style (str): The style string for the cell. |
| 306 | + secondary_key (str | None): An optional secondary string key to use for |
| 307 | + tie-breaking during sorting. |
| 308 | + """ |
| 309 | + |
| 310 | + safe_value = float("-inf") if value is None else float(value) |
| 311 | + super().__init__( |
| 312 | + _with_secondary_key(safe_value, secondary_key), |
| 313 | + as_bool(value=value), |
| 314 | + justification, |
| 315 | + style, |
| 316 | + ) |
| 317 | + |
| 318 | + |
187 | 319 | def _get_style_for_value(value: float) -> str: |
188 | 320 | """Get the style string based on the sign of a value. |
189 | 321 |
|
@@ -391,6 +523,90 @@ def _get_style_for_value(value: float) -> str: |
391 | 523 | ), |
392 | 524 | ) |
393 | 525 | ), |
| 526 | + "dividend_date": ( |
| 527 | + quote_column( |
| 528 | + "Div Date", |
| 529 | + full_name="Dividend Date", |
| 530 | + width=10, |
| 531 | + key="dividend_date", |
| 532 | + justification=Justify.LEFT, |
| 533 | + cell_factory=lambda q: DateCell( |
| 534 | + q.dividend_date, |
| 535 | + justification=Justify.LEFT, |
| 536 | + secondary_key=q.symbol or "", |
| 537 | + ), |
| 538 | + ) |
| 539 | + ), |
| 540 | + "market_state": ( |
| 541 | + quote_column( |
| 542 | + "Mkt State", |
| 543 | + full_name="Market State", |
| 544 | + width=10, |
| 545 | + key="market_state", |
| 546 | + justification=Justify.LEFT, |
| 547 | + cell_factory=lambda q: EnumCell( |
| 548 | + q.market_state, |
| 549 | + justification=Justify.LEFT, |
| 550 | + secondary_key=q.symbol or "", |
| 551 | + ), |
| 552 | + ) |
| 553 | + ), |
| 554 | + "option_type": ( |
| 555 | + quote_column( |
| 556 | + "Opt Type", |
| 557 | + full_name="Option Type", |
| 558 | + width=8, |
| 559 | + key="option_type", |
| 560 | + justification=Justify.LEFT, |
| 561 | + cell_factory=lambda q: EnumCell( |
| 562 | + q.option_type, |
| 563 | + justification=Justify.LEFT, |
| 564 | + secondary_key=q.symbol or "", |
| 565 | + ), |
| 566 | + ) |
| 567 | + ), |
| 568 | + "quote_type": ( |
| 569 | + quote_column( |
| 570 | + "Type", |
| 571 | + full_name="Quote Type", |
| 572 | + width=15, |
| 573 | + key="quote_type", |
| 574 | + justification=Justify.LEFT, |
| 575 | + cell_factory=lambda q: EnumCell( |
| 576 | + q.quote_type, |
| 577 | + justification=Justify.LEFT, |
| 578 | + secondary_key=q.symbol or "", |
| 579 | + ), |
| 580 | + ) |
| 581 | + ), |
| 582 | + "tradeable": ( |
| 583 | + quote_column( |
| 584 | + "Tradeable", |
| 585 | + full_name="Tradeable", |
| 586 | + width=9, |
| 587 | + key="tradeable", |
| 588 | + justification=Justify.CENTER, |
| 589 | + cell_factory=lambda q: BooleanCell( |
| 590 | + value=q.tradeable, |
| 591 | + justification=Justify.CENTER, |
| 592 | + secondary_key=q.symbol or "", |
| 593 | + ), |
| 594 | + ) |
| 595 | + ), |
| 596 | + "post_market_datetime": ( |
| 597 | + quote_column( |
| 598 | + "Post Mkt", |
| 599 | + full_name="Post-Market Datetime", |
| 600 | + width=16, |
| 601 | + key="post_market_datetime", |
| 602 | + justification=Justify.LEFT, |
| 603 | + cell_factory=lambda q: DateTimeCell( |
| 604 | + q.post_market_datetime, |
| 605 | + justification=Justify.LEFT, |
| 606 | + secondary_key=q.symbol or "", |
| 607 | + ), |
| 608 | + ) |
| 609 | + ), |
394 | 610 | } |
395 | 611 | """ |
396 | 612 | A dictionary that contains QuoteColumns available for the quote table. |
|
0 commit comments