### Calculate Initial Stability and Difficulty Source: https://open-spaced-repetition.github.io/py-fsrs Calculates the starting stability and difficulty values based on the provided rating. ```python def _initial_stability(self, *, rating: Rating) -> float: initial_stability = self.parameters[rating - 1] initial_stability = self._clamp_stability(stability=initial_stability) return initial_stability ``` ```python def _initial_difficulty(self, *, rating: Rating, clamp: bool) -> float: initial_difficulty = ( self.parameters[4] - (math.e ** (self.parameters[5] * (rating - 1))) + 1 ) if clamp: initial_difficulty = self._clamp_difficulty(difficulty=initial_difficulty) return initial_difficulty ``` -------------------------------- ### Optimizer class initialization Source: https://open-spaced-repetition.github.io/py-fsrs The Optimizer class requires the 'fsrs[optimizer]' extra to be installed. Attempting to instantiate it without this dependency raises an ImportError. ```python 668 class Optimizer: 669 def __init__(self, *args, **kwargs) -> None: 670 raise ImportError( 671 'Optimizer is not installed.\nInstall it with: pip install "fsrs[optimizer]"' 672 ) ``` ```python 669 def __init__(self, *args, **kwargs) -> None: 670 raise ImportError( 671 'Optimizer is not installed.\nInstall it with: pip install "fsrs[optimizer]"' 672 ) ``` -------------------------------- ### FSRS Review state transition with stability and difficulty update Source: https://open-spaced-repetition.github.io/py-fsrs Handles the Review state transition in the FSRS scheduler. Asserts that stability and difficulty are not None, then updates them using either short-term stability (if the review happened within the same day) or the regular next-stability calculation. Finally, it begins the interval calculation with a match on the rating, starting with the Again case for relearning steps. ```python case State.Review: assert card.stability is not None assert card.difficulty is not None # update the card's stability and difficulty if days_since_last_review is not None and days_since_last_review < 1: card.stability = self._short_term_stability( stability=card.stability, rating=rating ) else: card.stability = self._next_stability( difficulty=card.difficulty, stability=card.stability, retrievability=self.get_card_retrievability( card, current_datetime=review_datetime, ), rating=rating, ) card.difficulty = self._next_difficulty( difficulty=card.difficulty, rating=rating ) # calculate the card's next interval match rating: case Rating.Again: # if there are no relearning steps (they were left blank) ``` -------------------------------- ### Optimizer Source: https://open-spaced-repetition.github.io/py-fsrs Optimizer class that raises an ImportError if the optimizer is not installed. ```APIDOC ## Optimizer ### Description Optimizer class that raises an ImportError if the optimizer is not installed. ### Constructor Optimizer(*args, **kwargs) ### Behavior Raises ImportError with message: 'Optimizer is not installed.\nInstall it with: pip install "fsrs[optimizer]"' ``` -------------------------------- ### Card.__init__ Source: https://open-spaced-repetition.github.io/py-fsrs Initializes a new Card instance with optional parameters for card_id, state, step, stability, difficulty, due, and last_review. If card_id is not provided, it defaults to the current epoch milliseconds and waits 1ms to avoid collisions. ```APIDOC ## Card.__init__ ### Description Initializes a new Card instance with optional parameters. If card_id is not provided, it defaults to the current epoch milliseconds and waits 1ms to prevent collisions. ### Method Constructor ### Signature `Card(card_id: int | None = None, state: State = State.Learning, step: int | None = None, stability: float | None = None, difficulty: float | None = None, due: datetime | None = None, last_review: datetime | None = None) -> None` ### Parameters - **card_id** (int | None) - Optional - The id of the card. Defaults to epoch milliseconds of creation. - **state** (State) - Optional - The card's current learning state. Defaults to State.Learning. - **step** (int | None) - Optional - The card's current learning or relearning step. If state is Learning and step is None, step is set to 0. - **stability** (float | None) - Optional - Core mathematical parameter for future scheduling. - **difficulty** (float | None) - Optional - Core mathematical parameter for future scheduling. - **due** (datetime | None) - Optional - The date and time when the card is due next. Defaults to current UTC time. - **last_review** (datetime | None) - Optional - The date and time of the card's last review. ### Attributes - **card_id** (int) - The id of the card. - **state** (State) - The card's current learning state. - **step** (int | None) - The card's current learning or relearning step. - **stability** (float | None) - Core mathematical parameter. - **difficulty** (float | None) - Core mathematical parameter. - **due** (datetime) - The date and time when the card is due next. - **last_review** (datetime | None) - The date and time of the card's last review. ``` -------------------------------- ### Card.__init__ Source: https://open-spaced-repetition.github.io/py-fsrs Initializes a new Card instance with optional parameters for card_id, state, step, stability, difficulty, due, and last_review. Defaults are applied when parameters are not provided. ```APIDOC ## Card.__init__ ### Description Initializes a new Card instance with optional parameters. If card_id is not provided, it defaults to the current epoch milliseconds. If state is Learning and step is not provided, step defaults to 0. If due is not provided, it defaults to the current UTC datetime. ### Method Constructor ### Signature ```python Card(card_id: int | None = None, state: State = State.Learning, step: int | None = None, stability: float | None = None, difficulty: float | None = None, due: datetime | None = None, last_review: datetime | None = None) -> None ``` ### Parameters - **card_id** (int | None) - Optional - The id of the card. Defaults to epoch milliseconds of creation. - **state** (State) - Optional - The card's current learning state. Defaults to State.Learning. - **step** (int | None) - Optional - The current learning or relearning step. Defaults to 0 if state is Learning and step is None. - **stability** (float | None) - Optional - Core mathematical parameter for scheduling. - **difficulty** (float | None) - Optional - Core mathematical parameter for scheduling. - **due** (datetime | None) - Optional - The date and time when the card is due next. Defaults to current UTC datetime. - **last_review** (datetime | None) - Optional - The date and time of the card's last review. ### Returns None ``` -------------------------------- ### Initialize the FSRS Scheduler Source: https://open-spaced-repetition.github.io/py-fsrs The constructor sets up the scheduler with model parameters, desired retention, learning/relearning steps, maximum interval, and fuzzing configuration. ```python 165 def __init__( 166 self, 167 parameters: Sequence[float] = DEFAULT_PARAMETERS, 168 desired_retention: float = 0.9, 169 learning_steps: tuple[timedelta, ...] | list[timedelta] = ( 170 timedelta(minutes=1), 171 timedelta(minutes=10), 172 ), 173 relearning_steps: tuple[timedelta, ...] | list[timedelta] = ( 174 timedelta(minutes=10), 175 ), 176 maximum_interval: int = 36500, 177 enable_fuzzing: bool = True, 178 ) -> None: 179 self._validate_parameters(parameters=parameters) 180 181 self.parameters = tuple(parameters) 182 self.desired_retention = desired_retention 183 self.learning_steps = tuple(learning_steps) 184 self.relearning_steps = tuple(relearning_steps) 185 self.maximum_interval = maximum_interval 186 self.enable_fuzzing = enable_fuzzing 187 188 self._DECAY = -self.parameters[20] 189 self._FACTOR = 0.9 ** (1 / self._DECAY) - 1 ``` -------------------------------- ### Scheduler.__init__ Source: https://open-spaced-repetition.github.io/py-fsrs Initializes a Scheduler instance with configurable parameters for the FSRS algorithm, including model weights, desired retention, learning steps, relearning steps, maximum interval, and fuzzing. ```APIDOC ## Scheduler.__init__ ### Description Initializes a Scheduler instance with configurable parameters for the FSRS algorithm. ### Method Constructor ### Signature Scheduler(parameters: Sequence[float] = (0.212, 1.2931, 2.3065, 8.2956, 6.4133, 0.8334, 3.0194, 0.001, 1.8722, 0.1666, 0.796, 1.4835, 0.0614, 0.2629, 1.6483, 0.6014, 1.8729, 0.5425, 0.0912, 0.0658, 0.1542), desired_retention: float = 0.9, learning_steps: tuple[datetime.timedelta, ...] | list[datetime.timedelta] = (datetime.timedelta(seconds=60), datetime.timedelta(seconds=600)), relearning_steps: tuple[datetime.timedelta, ...] | list[datetime.timedelta] = (datetime.timedelta(seconds=600),), maximum_interval: int = 36500, enable_fuzzing: bool = True) ### Parameters - **parameters** (Sequence[float]) - Optional - The model weights of the FSRS scheduler. - **desired_retention** (float) - Optional - The desired retention rate of cards scheduled with the scheduler. - **learning_steps** (tuple[datetime.timedelta, ...] | list[datetime.timedelta]) - Optional - Small time intervals that schedule cards in the Learning state. - **relearning_steps** (tuple[datetime.timedelta, ...] | list[datetime.timedelta]) - Optional - Small time intervals that schedule cards in the Relearning state. - **maximum_interval** (int) - Optional - The maximum number of days a Review-state card can be scheduled into the future. - **enable_fuzzing** (bool) - Optional - Whether to apply a small amount of random 'fuzz' to calculated intervals. ### Attributes - **parameters** (tuple[float, ...]) - The model weights of the FSRS scheduler. - **desired_retention** (float) - The desired retention rate of cards scheduled with the scheduler. - **learning_steps** (tuple[datetime.timedelta, ...]) - Small time intervals that schedule cards in the Learning state. - **relearning_steps** (tuple[datetime.timedelta, ...]) - Small time intervals that schedule cards in the Relearning state. - **maximum_interval** (int) - The maximum number of days a Review-state card can be scheduled into the future. - **enable_fuzzing** (bool) - Whether to apply a small amount of random 'fuzz' to calculated intervals. ``` -------------------------------- ### Card Class Initialization Source: https://open-spaced-repetition.github.io/py-fsrs Initializes a new Card instance. If no card_id is provided, it defaults to the current epoch milliseconds. ```python 63 def __init__( 64 self, 65 card_id: int | None = None, 66 state: State = State.Learning, 67 step: int | None = None, 68 stability: float | None = None, 69 difficulty: float | None = None, 70 due: datetime | None = None, 71 last_review: datetime | None = None, 72 ) -> None: 73 if card_id is None: 74 # epoch milliseconds of when the card was created 75 card_id = int(datetime.now(timezone.utc).timestamp() * 1000) 76 # wait 1ms to prevent potential card_id collision on next Card creation 77 time.sleep(0.001) 78 self.card_id = card_id 79 80 self.state = state 81 82 if self.state == State.Learning and step is None: 83 step = 0 84 self.step = step 85 86 self.stability = stability 87 self.difficulty = difficulty 88 89 if due is None: 90 due = datetime.now(timezone.utc) 91 self.due = due 92 93 self.last_review = last_review ``` -------------------------------- ### Initialize py-fsrs module Source: https://open-spaced-repetition.github.io/py-fsrs This code defines the package structure and implements lazy loading for the Optimizer module to avoid heavy dependencies on initial import. ```python 1""" 2py-fsrs 3------- 4 5Py-FSRS is the official Python implementation of the FSRS scheduler algorithm, which can be used to develop spaced repetition systems. 6""" 7 8from typing import TYPE_CHECKING 9 10from fsrs.card import Card 11from fsrs.rating import Rating 12from fsrs.review_log import ReviewLog 13from fsrs.scheduler import Scheduler 14from fsrs.state import State 15 16if TYPE_CHECKING: 17 from fsrs.optimizer import Optimizer 18 19 20# lazy load the Optimizer module due to heavy dependencies 21def __getattr__(name: str) -> type: 22 if name == "Optimizer": 23 global Optimizer 24 from fsrs.optimizer import Optimizer 25 26 return Optimizer 27 raise AttributeError 28 29 30__all__ = ["Card", "Optimizer", "Rating", "ReviewLog", "Scheduler", "State"] ``` -------------------------------- ### Learning State Transition Logic Source: https://open-spaced-repetition.github.io/py-fsrs Handles the update of card stability, difficulty, and interval calculation when a card is in the Learning state. ```python 260 if review_datetime is not None and ( 261 (review_datetime.tzinfo is None) or (review_datetime.tzinfo != timezone.utc) 262 ): 263 raise ValueError("datetime must be timezone-aware and set to UTC") 264 265 card = copy(card) 266 267 if review_datetime is None: 268 review_datetime = datetime.now(timezone.utc) 269 270 days_since_last_review = ( 271 (review_datetime - card.last_review).days if card.last_review else None 272 ) 273 274 match card.state: 275 case State.Learning: 276 assert card.step is not None 277 278 # update the card's stability and difficulty 279 if card.stability is None or card.difficulty is None: 280 card.stability = self._initial_stability(rating=rating) 281 card.difficulty = self._initial_difficulty( 282 rating=rating, clamp=True 283 ) 284 285 elif days_since_last_review is not None and days_since_last_review < 1: 286 card.stability = self._short_term_stability( 287 stability=card.stability, rating=rating 288 ) 289 card.difficulty = self._next_difficulty( 290 difficulty=card.difficulty, rating=rating 291 ) 292 293 else: 294 card.stability = self._next_stability( 295 difficulty=card.difficulty, 296 stability=card.stability, 297 retrievability=self.get_card_retrievability( 298 card, 299 current_datetime=review_datetime, 300 ), 301 rating=rating, 302 ) 303 card.difficulty = self._next_difficulty( 304 difficulty=card.difficulty, rating=rating 305 ) 306 307 # calculate the card's next interval 308 ## first if-clause handles edge case where the Card in the Learning state was previously 309 ## scheduled with a Scheduler with more learning_steps than the current Scheduler 310 if len(self.learning_steps) == 0 or ( 311 card.step >= len(self.learning_steps) 312 and rating in (Rating.Hard, Rating.Good, Rating.Easy) 313 ): 314 card.state = State.Review 315 card.step = None 316 317 next_interval_days = self._next_interval(stability=card.stability) 318 next_interval = timedelta(days=next_interval_days) 319 320 else: 321 match rating: 322 case Rating.Again: 323 card.step = 0 324 next_interval = self.learning_steps[card.step] 325 326 case Rating.Hard: 327 # card step stays the same 328 329 if card.step == 0 and len(self.learning_steps) == 1: 330 next_interval = self.learning_steps[0] * 1.5 331 elif card.step == 0 and len(self.learning_steps) >= 2: 332 next_interval = ( 333 self.learning_steps[0] + self.learning_steps[1] 334 ) / 2.0 335 else: 336 next_interval = self.learning_steps[card.step] 337 338 case Rating.Good: 339 if card.step + 1 == len( 340 self.learning_steps 341 ): # the last step 342 card.state = State.Review 343 card.step = None 344 345 next_interval_days = self._next_interval( 346 stability=card.stability 347 ) 348 next_interval = timedelta(days=next_interval_days) 349 350 else: 351 card.step += 1 352 next_interval = self.learning_steps[card.step] 353 354 case Rating.Easy: 355 card.state = State.Review 356 card.step = None 357 358 next_interval_days = self._next_interval( 359 stability=card.stability 360 ) 361 next_interval = timedelta(days=next_interval_days) 362 363 case _: 364 raise ValueError(f"Unknown rating: {rating}") ``` -------------------------------- ### Scheduler.from_dict() - Create Scheduler from dictionary Source: https://open-spaced-repetition.github.io/py-fsrs Creates a Scheduler object from an existing dictionary. The dictionary must contain the keys parameters, desired_retention, learning_steps, relearning_steps, maximum_interval, and enable_fuzzing. Learning and relearning steps are converted from seconds to timedelta objects. ```python 584 @classmethod 585 def from_dict(cls, source_dict: SchedulerDict) -> Self: 586 """ 587 Creates a Scheduler object from an existing dictionary. 588 Args: 589 source_dict: A dictionary representing an existing Scheduler object. 590 Returns: 591 Self: A Scheduler object created from the provided dictionary. 592 """ 593 594 return cls( 595 parameters=source_dict["parameters"], 596 desired_retention=source_dict["desired_retention"], 597 learning_steps=[ 598 timedelta(seconds=learning_step) 599 for learning_step in source_dict["learning_steps"] 600 ], 601 relearning_steps=[ 602 timedelta(seconds=relearning_step) for relearning_step in source_dict["relearning_steps"] 603 ], 604 maximum_interval=source_dict["maximum_interval"], 605 enable_fuzzing=source_dict["enable_fuzzing"], 606 ) ``` -------------------------------- ### Handle Relearning State Transitions Source: https://open-spaced-repetition.github.io/py-fsrs Logic for updating card parameters and calculating the next interval when a card is in the Relearning state. ```python 415 case State.Relearning: 416 assert card.stability is not None 417 assert card.difficulty is not None 418 assert card.step is not None 419 420 # update the card's stability and difficulty 421 if days_since_last_review is not None and days_since_last_review < 1: 422 card.stability = self._short_term_stability( 423 stability=card.stability, rating=rating 424 ) 425 card.difficulty = self._next_difficulty( 426 difficulty=card.difficulty, rating=rating 427 ) 428 429 else: 430 card.stability = self._next_stability( 431 difficulty=card.difficulty, 432 stability=card.stability, 433 retrievability=self.get_card_retrievability( 434 card, 435 current_datetime=review_datetime, 436 ), 437 rating=rating, 438 ) 439 card.difficulty = self._next_difficulty( 440 difficulty=card.difficulty, rating=rating 441 ) 442 443 # calculate the card's next interval 444 ## first if-clause handles edge case where the Card in the Relearning state was previously 445 ## scheduled with a Scheduler with more relearning_steps than the current Scheduler 446 if len(self.relearning_steps) == 0 or ( 447 card.step >= len(self.relearning_steps) 448 and rating in (Rating.Hard, Rating.Good, Rating.Easy) 449 ): 450 card.state = State.Review 451 card.step = None 452 453 next_interval_days = self._next_interval(stability=card.stability) 454 next_interval = timedelta(days=next_interval_days) 455 456 else: 457 match rating: 458 case Rating.Again: 459 card.step = 0 460 next_interval = self.relearning_steps[card.step] 461 462 case Rating.Hard: 463 # card step stays the same 464 465 if card.step == 0 and len(self.relearning_steps) == 1: 466 next_interval = self.relearning_steps[0] * 1.5 467 elif card.step == 0 and len(self.relearning_steps) >= 2: 468 next_interval = ( ``` -------------------------------- ### FSRS.__init__ Source: https://open-spaced-repetition.github.io/py-fsrs Initializes an FSRS scheduler instance with configurable parameters for spaced repetition scheduling. ```APIDOC ## FSRS.__init__ ### Description Initializes an FSRS scheduler instance with configurable parameters for spaced repetition scheduling. ### Method Constructor ### Parameters - **parameters** (Sequence[float]) - Required - The FSRS algorithm parameters. - **desired_retention** (float) - Required - The desired retention rate. - **learning_steps** (tuple[timedelta, ...] | list[timedelta]) - Required - The learning steps as timedelta intervals. - **relearning_steps** (tuple[timedelta, ...] | list[timedelta]) - Required - The relearning steps as timedelta intervals. - **maximum_interval** (int) - Required - The maximum interval in days. - **enable_fuzzing** (bool) - Required - Whether to enable fuzzing. ### Raises - **ValueError** - If parameters are out of bounds or the number of parameters is incorrect. ``` -------------------------------- ### Handle Review State Transitions Source: https://open-spaced-repetition.github.io/py-fsrs Logic for updating card parameters and calculating the next interval when a card is in the Review state. ```python 366 case State.Review: 367 assert card.stability is not None 368 assert card.difficulty is not None 369 370 # update the card's stability and difficulty 371 if days_since_last_review is not None and days_since_last_review < 1: 372 card.stability = self._short_term_stability( 373 stability=card.stability, rating=rating 374 ) 375 else: 376 card.stability = self._next_stability( 377 difficulty=card.difficulty, 378 stability=card.stability, 379 retrievability=self.get_card_retrievability( 380 card, 381 current_datetime=review_datetime, 382 ), 383 rating=rating, 384 ) 385 386 card.difficulty = self._next_difficulty( 387 difficulty=card.difficulty, rating=rating 388 ) 389 390 # calculate the card's next interval 391 match rating: 392 case Rating.Again: 393 # if there are no relearning steps (they were left blank) 394 if len(self.relearning_steps) == 0: 395 next_interval_days = self._next_interval( 396 stability=card.stability 397 ) 398 next_interval = timedelta(days=next_interval_days) 399 400 else: 401 card.state = State.Relearning 402 card.step = 0 403 404 next_interval = self.relearning_steps[card.step] 405 406 case Rating.Hard | Rating.Good | Rating.Easy: 407 next_interval_days = self._next_interval( 408 stability=card.stability 409 ) 410 next_interval = timedelta(days=next_interval_days) 411 412 case _: 413 raise ValueError(f"Unknown rating: {rating}") ``` -------------------------------- ### Card Review Logic Implementation Source: https://open-spaced-repetition.github.io/py-fsrs Handles the state transitions and interval calculations for a card review based on the provided rating. ```python 469 self.relearning_steps[0] + self.relearning_steps[1] 470 ) / 2.0 471 else: 472 next_interval = self.relearning_steps[card.step] 473 474 case Rating.Good: 475 if card.step + 1 == len( 476 self.relearning_steps 477 ): # the last step 478 card.state = State.Review 479 card.step = None 480 481 next_interval_days = self._next_interval( 482 stability=card.stability 483 ) 484 next_interval = timedelta(days=next_interval_days) 485 486 else: 487 card.step += 1 488 next_interval = self.relearning_steps[card.step] 489 490 case Rating.Easy: 491 card.state = State.Review 492 card.step = None 493 494 next_interval_days = self._next_interval( 495 stability=card.stability 496 ) 497 next_interval = timedelta(days=next_interval_days) 498 499 case _: 500 raise ValueError(f"Unknown rating: {rating}") 501 502 case _: 503 raise ValueError(f"Unknown card state: {card.state}") 504 505 if self.enable_fuzzing and card.state == State.Review: 506 next_interval = self._get_fuzzed_interval(interval=next_interval) 507 508 card.due = review_datetime + next_interval 509 card.last_review = review_datetime 510 511 review_log = ReviewLog( 512 card_id=card.card_id, 513 rating=rating, 514 review_datetime=review_datetime, 515 review_duration=review_duration, 516 ) 517 518 return card, review_log ``` -------------------------------- ### ReviewLog.from_dict class method Source: https://open-spaced-repetition.github.io/py-fsrs Creates a ReviewLog object from an existing dictionary. ```python 70 @classmethod 71 def from_dict( 72 cls, 73 source_dict: ReviewLogDict, 74 ) -> Self: 75 """ 76 Creates a ReviewLog object from an existing dictionary. 77 78 Args: 79 source_dict: A dictionary representing an existing ReviewLog object. 80 81 Returns: 82 Self: A ReviewLog object created from the provided dictionary. 83 """ 84 85 return cls( 86 card_id=source_dict["card_id"], 87 rating=Rating(int(source_dict["rating"])), 88 review_datetime=datetime.fromisoformat(source_dict["review_datetime"]), 89 review_duration=source_dict["review_duration"], 90 ) ``` -------------------------------- ### from_dict class method Source: https://open-spaced-repetition.github.io/py-fsrs Creates a new Scheduler instance from a dictionary. This is the inverse of the to_dict method. ```python @classmethod def from_dict(cls, source_dict: SchedulerDict) -> Self: """ Creates a Scheduler object from an existing dictionary. Args: source_dict: A dictionary representing an existing Scheduler object. Returns: Self: A Scheduler object created from the provided dictionary. """ return cls( parameters=source_dict["parameters"], desired_retention=source_dict["desired_retention"], learning_steps=[ timedelta(seconds=learning_step) for learning_step in source_dict["learning_steps"] ], relearning_steps=[ timedelta(seconds=relearning_step) for relearning_step in source_dict["relearning_steps"] ], maximum_interval=source_dict["maximum_interval"], enable_fuzzing=source_dict["enable_fuzzing"], ) ``` -------------------------------- ### FSRS Learning state transition with rating match Source: https://open-spaced-repetition.github.io/py-fsrs Handles the Learning state transition in the FSRS scheduler. If there are no learning steps or the card has passed all steps with a Hard, Good, or Easy rating, it moves to Review and computes the next interval from stability. Otherwise, it applies the rating-specific logic: Again resets to step 0, Hard keeps the step or averages the first two steps, Good advances to the next step or moves to Review on the last step, and Easy moves directly to Review. Raises ValueError for unknown ratings. ```python if len(self.learning_steps) == 0 or ( card.step >= len(self.learning_steps) and rating in (Rating.Hard, Rating.Good, Rating.Easy) ): card.state = State.Review card.step = None next_interval_days = self._next_interval(stability=card.stability) next_interval = timedelta(days=next_interval_days) else: match rating: case Rating.Again: card.step = 0 next_interval = self.learning_steps[card.step] case Rating.Hard: # card step stays the same if card.step == 0 and len(self.learning_steps) == 1: next_interval = self.learning_steps[0] * 1.5 elif card.step == 0 and len(self.learning_steps) >= 2: next_interval = ( self.learning_steps[0] + self.learning_steps[1] ) / 2.0 else: next_interval = self.learning_steps[card.step] case Rating.Good: if card.step + 1 == len( self.learning_steps ): # the last step card.state = State.Review card.step = None next_interval_days = self._next_interval( stability=card.stability ) next_interval = timedelta(days=next_interval_days) else: card.step += 1 next_interval = self.learning_steps[card.step] case Rating.Easy: card.state = State.Review card.step = None next_interval_days = self._next_interval( stability=card.stability ) next_interval = timedelta(days=next_interval_days) case _: raise ValueError(f"Unknown rating: {rating}") ``` -------------------------------- ### from_dict(source_dict) Source: https://open-spaced-repetition.github.io/py-fsrs Creates a Scheduler object from an existing dictionary. ```APIDOC ## from_dict(source_dict) ### Description Creates a Scheduler object from an existing dictionary. ### Method from_dict ### Parameters - **source_dict** (SchedulerDict) - Required - A dictionary representing an existing Scheduler object. ### Returns - **Self** - A Scheduler object created from the provided dictionary. ``` -------------------------------- ### Scheduler.from_dict(source_dict) Source: https://open-spaced-repetition.github.io/py-fsrs Creates a Scheduler object from an existing dictionary. ```APIDOC ## Scheduler.from_dict(source_dict) ### Description Creates a Scheduler object from an existing dictionary. ### Parameters - **source_dict** (SchedulerDict) - Required - A dictionary representing an existing Scheduler object. ### Returns - **Self** - A Scheduler object created from the provided dictionary. ``` -------------------------------- ### Scheduler.from_json() - Create Scheduler from JSON string Source: https://open-spaced-repetition.github.io/py-fsrs Creates a Scheduler object from a JSON-serialized string. The source_json is parsed with json.loads and then passed to from_dict(). ```python 624 @classmethod 625 def from_json(cls, source_json: str) -> Self: 626 """ 627 Creates a Scheduler object from a JSON-serialized string. 628 Args: 629 source_json: A JSON-serialized string of an existing Scheduler object. 630 Returns: 631 Self: A Scheduler object created from the JSON string. 632 """ 633 634 source_dict: SchedulerDict = json.loads(source_json) 635 return cls.from_dict(source_dict=source_dict) ``` -------------------------------- ### Scheduler.from_json(source_json) Source: https://open-spaced-repetition.github.io/py-fsrs Creates a Scheduler object from a JSON-serialized string. ```APIDOC ## Scheduler.from_json(source_json) ### Description Creates a Scheduler object from a JSON-serialized string. ### Parameters - **source_json** (str) - Required - A JSON-serialized string of an existing Scheduler object. ### Returns - **Self** - A Scheduler object created from the JSON string. ``` -------------------------------- ### ReviewLog.from_dict Source: https://open-spaced-repetition.github.io/py-fsrs Creates a ReviewLog object from an existing dictionary. ```APIDOC ## ReviewLog.from_dict ### Description Creates a ReviewLog object from an existing dictionary. ### Method ReviewLog.from_dict (classmethod) ### Parameters - **source_dict** (ReviewLogDict) - Required - A dictionary representing an existing ReviewLog object. ### Returns - **Self** - A ReviewLog object created from the provided dictionary. ``` -------------------------------- ### ReviewLog.from_dict Source: https://open-spaced-repetition.github.io/py-fsrs Creates a ReviewLog object from an existing dictionary. ```APIDOC ## ReviewLog.from_dict ### Description Creates a ReviewLog object from an existing dictionary. ### Method `from_dict(cls, source_dict: ReviewLogDict) -> Self` ### Parameters - **source_dict** (ReviewLogDict) - Required - A dictionary representing an existing ReviewLog object. ### Returns - **Self**: A ReviewLog object created from the provided dictionary. ### Example ```python source_dict = {"card_id": 1, "rating": 3, "review_datetime": "2023-01-01T00:00:00", "review_duration": 1000} review_log = ReviewLog.from_dict(source_dict) ``` ``` -------------------------------- ### ReviewLog class and methods Source: https://open-spaced-repetition.github.io/py-fsrs Represents a review log entry with methods for dictionary and JSON serialization/deserialization. ```python 36@dataclass 37class ReviewLog: 38 """ 39 Represents the log entry of a Card object that has been reviewed. 40 41 Attributes: 42 card_id: The id of the card being reviewed. 43 rating: The rating given to the card during the review. 44 review_datetime: The date and time of the review. 45 review_duration: The number of milliseconds it took to review the card or None if unspecified. 46 """ 47 48 card_id: int 49 rating: Rating 50 review_datetime: datetime 51 review_duration: int | None 52 53 def to_dict( 54 self, 55 ) -> ReviewLogDict: 56 """ 57 Returns a dictionary representation of the ReviewLog object. 58 59 Returns: 60 ReviewLogDict: A dictionary representation of the ReviewLog object. 61 """ 62 63 return { 64 "card_id": self.card_id, 65 "rating": int(self.rating), 66 "review_datetime": self.review_datetime.isoformat(), 67 "review_duration": self.review_duration, 68 } 69 70 @classmethod 71 def from_dict( 72 cls, 73 source_dict: ReviewLogDict, 74 ) -> Self: 75 """ 76 Creates a ReviewLog object from an existing dictionary. 77 78 Args: 79 source_dict: A dictionary representing an existing ReviewLog object. 80 81 Returns: 82 Self: A ReviewLog object created from the provided dictionary. 83 """ 84 85 return cls( 86 card_id=source_dict["card_id"], 87 rating=Rating(int(source_dict["rating"])), 88 review_datetime=datetime.fromisoformat(source_dict["review_datetime"]), 89 review_duration=source_dict["review_duration"], 90 ) 91 92 def to_json(self, indent: int | str | None = None) -> str: 93 """ 94 Returns a JSON-serialized string of the ReviewLog object. 95 96 Args: 97 indent: Equivalent argument to the indent in json.dumps() 98 99 Returns: 100 str: A JSON-serialized string of the ReviewLog object. 101 """ 102 103 return json.dumps(self.to_dict(), indent=indent) 104 105 @classmethod 106 def from_json(cls, source_json: str) -> Self: 107 """ 108 Creates a ReviewLog object from a JSON-serialized string. 109 110 Args: 111 source_json: A JSON-serialized string of an existing ReviewLog object. 112 113 Returns: 114 Self: A ReviewLog object created from the JSON string. 115 """ 116 117 source_dict: ReviewLogDict = json.loads(source_json) 118 return cls.from_dict(source_dict=source_dict) ``` -------------------------------- ### ReviewLog.to_dict method Source: https://open-spaced-repetition.github.io/py-fsrs Returns a dictionary representation of the ReviewLog object. ```python 53 def to_dict( 54 self, 55 ) -> ReviewLogDict: 56 """ 57 Returns a dictionary representation of the ReviewLog object. 58 59 Returns: 60 ReviewLogDict: A dictionary representation of the ReviewLog object. 61 """ 62 63 return { 64 "card_id": self.card_id, 65 "rating": int(self.rating), 66 "review_datetime": self.review_datetime.isoformat(), 67 "review_duration": self.review_duration, 68 } ``` -------------------------------- ### Clamp Difficulty and Stability Source: https://open-spaced-repetition.github.io/py-fsrs Utility methods to constrain difficulty and stability values within defined global bounds. ```python @overload def _clamp_difficulty(self, *, difficulty: float) -> float: ... @overload def _clamp_difficulty(self, *, difficulty: Tensor) -> Tensor: ... def _clamp_difficulty(self, *, difficulty: float | Tensor) -> float | Tensor: if isinstance(difficulty, (int, float)): difficulty = min(max(difficulty, MIN_DIFFICULTY), MAX_DIFFICULTY) else: difficulty = difficulty.clamp(min=MIN_DIFFICULTY, max=MAX_DIFFICULTY) return difficulty ``` ```python @overload def _clamp_stability(self, *, stability: float) -> float: ... @overload def _clamp_stability(self, *, stability: Tensor) -> Tensor: ... def _clamp_stability(self, *, stability: float | Tensor) -> float | Tensor: if isinstance(stability, (int, float)): stability = max(stability, STABILITY_MIN) else: stability = stability.clamp(min=STABILITY_MIN) return stability ``` -------------------------------- ### Card.to_dict Source: https://open-spaced-repetition.github.io/py-fsrs Returns a dictionary representation of the Card object, converting the due and last_review datetimes to ISO format strings. ```APIDOC ## Card.to_dict ### Description Returns a dictionary representation of the Card object. The due field is converted to an ISO format string, and last_review is converted to an ISO format string if not None. ### Method Instance Method ### Signature ```python def to_dict(self) -> CardDict ``` ### Parameters None ### Returns - **CardDict** - A dictionary containing the card's attributes: card_id (int), state (int, the value of the State enum), step (int | None), stability (float | None), difficulty (float | None), due (str, ISO format), last_review (str | None, ISO format). ``` -------------------------------- ### ReviewLog.from_json Source: https://open-spaced-repetition.github.io/py-fsrs Creates a ReviewLog object from a JSON-serialized string. ```APIDOC ## ReviewLog.from_json ### Description Creates a ReviewLog object from a JSON-serialized string. ### Method ReviewLog.from_json (classmethod) ### Parameters - **source_json** (str) - Required - A JSON-serialized string of an existing ReviewLog object. ### Returns - **Self** - A ReviewLog object created from the JSON string. ``` -------------------------------- ### ReviewLog.from_json Source: https://open-spaced-repetition.github.io/py-fsrs Creates a ReviewLog object from a JSON-serialized string. ```APIDOC ## ReviewLog.from_json ### Description Creates a ReviewLog object from a JSON-serialized string. ### Method `from_json(cls, source_json: str) -> Self` ### Parameters - **source_json** (str) - Required - A JSON-serialized string of an existing ReviewLog object. ### Returns - **Self**: A ReviewLog object created from the JSON string. ### Example ```python json_str = '{"card_id": 1, "rating": 3, "review_datetime": "2023-01-01T00:00:00", "review_duration": 1000}' review_log = ReviewLog.from_json(json_str) ``` ``` -------------------------------- ### ReviewLog.from_json class method Source: https://open-spaced-repetition.github.io/py-fsrs Creates a ReviewLog object from a JSON-serialized string. ```python 105 @classmethod 106 def from_json(cls, source_json: str) -> Self: 107 """ 108 Creates a ReviewLog object from a JSON-serialized string. 109 110 Args: 111 source_json: A JSON-serialized string of an existing ReviewLog object. 112 113 Returns: 114 Self: A ReviewLog object created from the JSON string. 115 """ 116 117 source_dict: ReviewLogDict = json.loads(source_json) 118 return cls.from_dict(source_dict=source_dict) ``` -------------------------------- ### to_json(indent) Source: https://open-spaced-repetition.github.io/py-fsrs Returns a JSON-serialized string of the Scheduler object. ```APIDOC ## to_json(indent) ### Description Returns a JSON-serialized string of the Scheduler object. ### Method to_json ### Parameters - **indent** (int | str | None) - Optional - Equivalent argument to the indent in json.dumps(). ### Returns - **str** - A JSON-serialized string of the Scheduler object. ``` -------------------------------- ### Scheduler.to_json(indent=None) Source: https://open-spaced-repetition.github.io/py-fsrs Returns a JSON-serialized string of the Scheduler object. ```APIDOC ## Scheduler.to_json(indent=None) ### Description Returns a JSON-serialized string of the Scheduler object. ### Parameters - **indent** (int | str | None) - Optional - Equivalent argument to the indent in json.dumps(). ### Returns - **str** - A JSON-serialized string of the Scheduler object. ``` -------------------------------- ### review_card(card, rating, review_datetime, review_duration) Source: https://open-spaced-repetition.github.io/py-fsrs Reviews a card with the given rating and updates its scheduling state. Returns the updated card and a review log. ```APIDOC ## review_card(card, rating, review_datetime, review_duration) ### Description Reviews a card with the given rating and updates its scheduling state. Returns the updated card and a review log. ### Method review_card ### Parameters - **card** (Card) - Required - The card to be reviewed. - **rating** (Rating) - Required - The rating given by the user. - **review_datetime** (datetime) - Required - The datetime of the review. - **review_duration** (timedelta) - Optional - The duration of the review. ### Returns - **Card** - The updated card. - **ReviewLog** - The review log for this review. ### Raises - **ValueError** - If the rating or card state is unknown. ``` -------------------------------- ### Calculate Next Difficulty Source: https://open-spaced-repetition.github.io/py-fsrs Computes the next difficulty level using linear damping and mean reversion. ```python def _next_difficulty(self, *, difficulty: float, rating: Rating) -> float: def _linear_damping(*, delta_difficulty: float, difficulty: float) -> float: return (10.0 - difficulty) * delta_difficulty / 9.0 def _mean_reversion(*, arg_1: float, arg_2: float) -> float: return self.parameters[7] * arg_1 + (1 - self.parameters[7]) * arg_2 arg_1 = self._initial_difficulty(rating=Rating.Easy, clamp=False) delta_difficulty = -(self.parameters[6] * (rating - 3)) arg_2 = difficulty + _linear_damping( delta_difficulty=delta_difficulty, difficulty=difficulty ) next_difficulty = _mean_reversion(arg_1=arg_1, arg_2=arg_2) next_difficulty = self._clamp_difficulty(difficulty=next_difficulty) return next_difficulty ``` -------------------------------- ### ReviewLog.to_json method Source: https://open-spaced-repetition.github.io/py-fsrs Returns a JSON-serialized string of the ReviewLog object. ```python 92 def to_json(self, indent: int | str | None = None) -> str: 93 """ 94 Returns a JSON-serialized string of the ReviewLog object. 95 96 Args: 97 indent: Equivalent argument to the indent in json.dumps() 98 99 Returns: 100 str: A JSON-serialized string of the ReviewLog object. 101 """ 102 103 return json.dumps(self.to_dict(), indent=indent) ``` -------------------------------- ### Create Scheduler from JSON Source: https://open-spaced-repetition.github.io/py-fsrs Deserializes a JSON string into a Scheduler object. ```python def from_json(cls, source_json: str) -> Self: """ Creates a Scheduler object from a JSON-serialized string. Args: source_json: A JSON-serialized string of an existing Scheduler object. Returns: Self: A Scheduler object created from the JSON string. """ source_dict: SchedulerDict = json.loads(source_json) return cls.from_dict(source_dict=source_dict) ``` -------------------------------- ### ReviewLog.to_dict Source: https://open-spaced-repetition.github.io/py-fsrs Returns a dictionary representation of the ReviewLog object. ```APIDOC ## ReviewLog.to_dict ### Description Returns a dictionary representation of the ReviewLog object. ### Method ReviewLog.to_dict ### Returns - **ReviewLogDict** - A dictionary representation of the ReviewLog object. ``` -------------------------------- ### to_dict method Source: https://open-spaced-repetition.github.io/py-fsrs Converts the Scheduler object into a dictionary representation, including parameters, retention settings, and interval steps. ```python def to_dict( self, ) -> SchedulerDict: """ Returns a dictionary representation of the Scheduler object. Returns: SchedulerDict: A dictionary representation of the Scheduler object. """ return { "parameters": list(self.parameters), "desired_retention": self.desired_retention, "learning_steps": [ int(learning_step.total_seconds()) for learning_step in self.learning_steps ], "relearning_steps": [ int(relearning_step.total_seconds()) for relearning_step in self.relearning_steps ], "maximum_interval": self.maximum_interval, "enable_fuzzing": self.enable_fuzzing, } ``` -------------------------------- ### to_dict() Source: https://open-spaced-repetition.github.io/py-fsrs Returns a dictionary representation of the Scheduler object. ```APIDOC ## to_dict() ### Description Returns a dictionary representation of the Scheduler object. ### Method to_dict ### Returns - **SchedulerDict** - A dictionary representation of the Scheduler object. ``` -------------------------------- ### Scheduler.to_dict() Source: https://open-spaced-repetition.github.io/py-fsrs Returns a dictionary representation of the Scheduler object. ```APIDOC ## Scheduler.to_dict() ### Description Returns a dictionary representation of the Scheduler object. ### Returns - **SchedulerDict** - A dictionary representation of the Scheduler object. ```