195 lines
7.5 KiB
Python
195 lines
7.5 KiB
Python
"""
|
|
Miscellaneous utilities for Tarot, including personality typing and other tools.
|
|
|
|
This module contains specialized utilities that don't fit into other categories.
|
|
"""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Optional, TYPE_CHECKING
|
|
from enum import Enum
|
|
|
|
if TYPE_CHECKING:
|
|
from tarot.deck.deck import CourtCard
|
|
|
|
|
|
class MBTIType(Enum):
|
|
"""16 MBTI personality types."""
|
|
ISTJ = "ISTJ"
|
|
ISFJ = "ISFJ"
|
|
INFJ = "INFJ"
|
|
INTJ = "INTJ"
|
|
ISTP = "ISTP"
|
|
ISFP = "ISFP"
|
|
INFP = "INFP"
|
|
INTP = "INTP"
|
|
ESTP = "ESTP"
|
|
ESFP = "ESFP"
|
|
ENFP = "ENFP"
|
|
ENTP = "ENTP"
|
|
ESTJ = "ESTJ"
|
|
ESFJ = "ESFJ"
|
|
ENFJ = "ENFJ"
|
|
ENTJ = "ENTJ"
|
|
|
|
|
|
@dataclass
|
|
class Personality:
|
|
"""
|
|
MBTI Personality Type mapped to a specific Tarot Court Card.
|
|
|
|
This class creates a direct 1-to-1 relationship between each of the 16 MBTI
|
|
personality types and their corresponding Tarot court cards. Based on the
|
|
comprehensive system developed by Dante DiMatteo at 78 Revelations Per Minute:
|
|
https://78revelationsaminute.wordpress.com/2015/07/08/personality-types-the-tarot-court-cards-and-the-myers-briggs-type-indicator/
|
|
|
|
The mapping is based on:
|
|
- SUITS correspond to Jung's 4 cognitive functions:
|
|
* Wands: Intuition (N)
|
|
* Cups: Feeling (F)
|
|
* Swords: Thinking (T)
|
|
* Pentacles: Sensation (S)
|
|
|
|
- RANKS correspond to MBTI traits:
|
|
* Kings (E + J): Extraverted Judgers
|
|
* Queens (I + J): Introverted Judgers
|
|
* Princes (E + P): Extraverted Perceivers
|
|
* Princesses (I + P): Introverted Perceivers
|
|
|
|
Attributes:
|
|
mbti_type: The MBTI personality type (e.g., ENFP)
|
|
court_card: The single CourtCard object representing this personality
|
|
description: Brief description of the personality archetype
|
|
"""
|
|
|
|
mbti_type: MBTIType
|
|
court_card: Optional['CourtCard'] = None
|
|
description: str = ""
|
|
|
|
# Direct MBTI-to-CourtCard mapping (1-to-1 relationship)
|
|
# Format: MBTI_TYPE -> (Rank, Suit)
|
|
_MBTI_TO_CARD_MAPPING = {
|
|
# KINGS (E + J) - Extraverted Judgers
|
|
"ENTJ": ("Knight", "Wands"), # Fiery, forceful leadership
|
|
"ENFJ": ("Knight", "Cups"), # Sensitive, mission-driven
|
|
"ESTJ": ("Knight", "Swords"), # Practical, pragmatic
|
|
"ESFJ": ("Knight", "Pentacles"), # Sociable, consensus-seeking
|
|
|
|
# QUEENS (I + J) - Introverted Judgers
|
|
"INTJ": ("Queen", "Wands"), # Analytical, self-motivated
|
|
"INFJ": ("Queen", "Cups"), # Sensitive, interconnected
|
|
"ISTJ": ("Queen", "Swords"), # Pragmatic, duty-fulfiller
|
|
"ISFJ": ("Queen", "Pentacles"), # Caring, earth-mother type
|
|
|
|
# PRINCES (E + P) - Extraverted Perceivers
|
|
"ENTP": ("Prince", "Wands"), # Visionary, quick-study
|
|
"ENFP": ("Prince", "Cups"), # Inspiring, intuitive
|
|
"ESTP": ("Prince", "Swords"), # Action-oriented, risk-taker
|
|
"ESFP": ("Prince", "Pentacles"), # Aesthete, sensualist
|
|
|
|
# PRINCESSES (I + P) - Introverted Perceivers
|
|
"INTP": ("Princess", "Wands"), # Thinker par excellence
|
|
"INFP": ("Princess", "Cups"), # Idealistic, devoted
|
|
"ISTP": ("Princess", "Swords"), # Observer, mechanic
|
|
"ISFP": ("Princess", "Pentacles"), # Aesthete, free spirit
|
|
}
|
|
|
|
@classmethod
|
|
def from_mbti(cls, mbti_type: str, deck: Optional[object] = None) -> 'Personality':
|
|
"""
|
|
Create a Personality from an MBTI type string.
|
|
|
|
Args:
|
|
mbti_type: MBTI type as string (e.g., "ENFP", "ISTJ")
|
|
deck: Optional Tarot Deck to fetch the court card from. If not provided,
|
|
court card will be fetched dynamically when accessed.
|
|
|
|
Returns:
|
|
Personality object with associated court card
|
|
|
|
Raises:
|
|
ValueError: If mbti_type is not a valid MBTI type
|
|
|
|
Example:
|
|
>>> from tarot import Tarot
|
|
>>> personality = Personality.from_mbti("ENFP", Tarot.deck)
|
|
>>> print(personality.mbti_type.value)
|
|
ENFP
|
|
>>> print(f"{personality.court_card.court_rank} of {personality.court_card.suit.name}")
|
|
Prince of Cups
|
|
"""
|
|
mbti_type = mbti_type.upper()
|
|
|
|
# Validate MBTI type
|
|
try:
|
|
mbti_enum = MBTIType[mbti_type]
|
|
except KeyError:
|
|
raise ValueError(
|
|
f"Invalid MBTI type: {mbti_type}. Must be one of: "
|
|
f"{', '.join([t.value for t in MBTIType])}"
|
|
)
|
|
|
|
# Get the rank and suit for this MBTI type
|
|
rank, suit = cls._MBTI_TO_CARD_MAPPING.get(mbti_type, (None, None))
|
|
if not rank or not suit:
|
|
raise ValueError(f"No court card mapping found for MBTI type {mbti_type}")
|
|
|
|
# Get court card from deck if provided
|
|
court_card = None
|
|
if deck is not None:
|
|
# Import here to avoid circular imports
|
|
from tarot import Tarot
|
|
|
|
# Use provided deck or default to Tarot
|
|
d = deck if hasattr(deck, 'card') else Tarot.deck
|
|
|
|
cards = d.card.filter(type="Court", court_rank=rank, suit=suit)
|
|
if cards:
|
|
court_card = cards[0]
|
|
|
|
# Get description
|
|
descriptions = {
|
|
"ENTJ": "The Commander - Strategic, ambitious, leader of Wands",
|
|
"ENFJ": "The Protagonist - Inspiring, empathetic, leader of Cups",
|
|
"ESTJ": "The Supervisor - Practical, decisive, leader of Swords",
|
|
"ESFJ": "The Consul - Sociable, cooperative, leader of Pentacles",
|
|
|
|
"INTJ": "The Architect - Strategic, logical, sage of Wands",
|
|
"INFJ": "The Advocate - Insightful, idealistic, sage of Cups",
|
|
"ISTJ": "The Logistician - Practical, reliable, sage of Swords",
|
|
"ISFJ": "The Defender - Caring, conscientious, sage of Pentacles",
|
|
|
|
"ENTP": "The Debater - Innovative, quick-witted, explorer of Wands",
|
|
"ENFP": "The Campaigner - Enthusiastic, social, explorer of Cups",
|
|
"ESTP": "The Entrepreneur - Energetic, bold, explorer of Swords",
|
|
"ESFP": "The Entertainer - Spontaneous, outgoing, explorer of Pentacles",
|
|
|
|
"INTP": "The Logician - Analytical, curious, seeker of Wands",
|
|
"INFP": "The Mediator - Idealistic, authentic, seeker of Cups",
|
|
"ISTP": "The Virtuoso - Practical, observant, seeker of Swords",
|
|
"ISFP": "The Adventurer - Sensitive, spontaneous, seeker of Pentacles",
|
|
}
|
|
|
|
return cls(
|
|
mbti_type=mbti_enum,
|
|
court_card=court_card,
|
|
description=descriptions.get(mbti_type, "")
|
|
)
|
|
|
|
def __str__(self) -> str:
|
|
"""Return string representation of personality with court card."""
|
|
if self.court_card:
|
|
card_str = f"{self.court_card.court_rank} of {self.court_card.suit.name}"
|
|
else:
|
|
card_str = "No court card loaded"
|
|
|
|
return f"{self.mbti_type.value} - {self.description}\n Court Card: {card_str}"
|
|
|
|
def __repr__(self) -> str:
|
|
"""Return detailed representation."""
|
|
card_name = (
|
|
f"{self.court_card.court_rank} of {self.court_card.suit.name}"
|
|
if self.court_card
|
|
else "None"
|
|
)
|
|
return f"Personality(mbti_type={self.mbti_type.value}, court_card={card_name})"
|