Skip to content

Commit

Permalink
v3.0.0 update
Browse files Browse the repository at this point in the history
  • Loading branch information
alankan886 committed Jun 23, 2024
1 parent 80affaf commit d615f6e
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 149 deletions.
20 changes: 10 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
name: CI
on:
push:
branches: ["master"]
branches: ["main"]
pull_request:
branches: ["master"]
branches: ["main"]
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: [3.5, 3.6, 3.7, 3.8, 3.9]
python-version: [3.7, 3.8, 3.9, 3.10, 3.11, 3.12]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Generate coverage report
run: |
python -m pip install --upgrade pip
pip install pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pytest
upload_coverage:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: '3.9'
python-version: '3.10'
- name: Generate coverage report
run: |
python -m pip install --upgrade pip
pip install pytest-cov
pytest --cov=supermemo2 --cov-report=xml
- name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v4
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# SuperMemo2
![Python](https://img.shields.io/badge/python-3+-blue.svg?logo=python&longCache=true&logoColor=white&colorB=5e81ac&style=flat-square&colorA=4c566a)
![Python](https://img.shields.io/badge/python-3.7+-blue.svg?logo=python&longCache=true&logoColor=white&colorB=5e81ac&style=flat-square&colorA=4c566a)
[![Version](https://img.shields.io/pypi/v/supermemo2?logo=pypi&logoColor=white&style=flat-square&colorA=4c566a&colorB=90A2BC)](https://pypi.org/project/supermemo2/)
[![Build](https://img.shields.io/github/workflow/status/alankan886/SuperMemo2/CI?logo=github-actions&logoColor=white&style=flat-square&colorA=4c566a&colorB=90BCA8)](https://github.com/alankan886/SuperMemo2/actions?query=workflow%3ACI)
[![Coverage](https://img.shields.io/codecov/c/github/alankan886/SuperMemo2?logo=codecov&logoColor=white&style=flat-square&colorA=4c566a&colorB=90BCA8)](https://codecov.io/gh/alankan886/SuperMemo2)
Expand Down Expand Up @@ -52,23 +52,23 @@ Install dependencies to run the code:
pip3 install -r requirements.txt
```

supermemo2 supports Python 3+
supermemo2 supports Python 3.7+

<a name="example">

## A Simple Example

```python
from supermemo2 import SMTwo
from supermemo2 import first_review, review

# first review
# using quality=4 as an example, read below for what each value from 0 to 5 represents
# review date would default to date.today() if not provided
review = SMTwo.first_review(4, "2021-3-14")
# review prints SMTwo(easiness=2.36, interval=1, repetitions=1, review_date=datetime.date(2021, 3, 15))
# review date would default to datetime.utcnow() if not provided
first_review = first_review(4, "2021-3-14")
# review prints { "easiness": 2.36, "interval": 1, "repetitions": 1, "review_datetime": "2024-06-23 01:06:02"))

# second review
review = SMTwo(review.easiness, review.interval, review.repetitions).review(4, "2021-3-14")
second_review = review(4, first_review["easiness"], first_review["interval"], first_review["repetitions"], first_review["review_datetime"])
# review prints similar to example above.
```

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pytest-cov==2.10.1

freezegun==1.5.1
100 changes: 42 additions & 58 deletions supermemo2/sm_two.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,53 @@
from math import ceil
from datetime import date, datetime, timedelta
from datetime import datetime, timedelta
from typing import Optional, Union, Dict

import attr

def review(
quality: int,
easiness: float,
interval: int,
repetitions: int,
review_datetime: Optional[Union[datetime, str]] = None,
) -> Dict:
if not review_datetime:
review_datetime = datetime.utcnow().isoformat(sep=" ", timespec="seconds")

if isinstance(review_datetime, str):
review_datetime = datetime.fromisoformat(review_datetime).replace(microsecond=0)

if quality < 3:
interval = 1
repetitions = 0
else:
if repetitions == 0:
interval = 1
elif repetitions == 1:
interval = 6
else:
interval = ceil(interval * easiness)

year_mon_day = "%Y-%m-%d"
mon_day_year = "%m-%d-%Y"
day_mon_year = "%d-%m-%Y"


@attr.s
class SMTwo:
easiness = attr.ib(validator=attr.validators.instance_of(float))
interval = attr.ib(validator=attr.validators.instance_of(int))
repetitions = attr.ib(validator=attr.validators.instance_of(int))
review_date = attr.ib(init=False)

@staticmethod
def first_review(
quality: int,
review_date: Optional[Union[date, str]] = None,
date_fmt: Optional[str] = None,
) -> "SMTwo":
if not review_date:
review_date = date.today()

if not date_fmt:
date_fmt = year_mon_day

return SMTwo(2.5, 0, 0).review(quality, review_date, date_fmt)

def review(
self,
quality: int,
review_date: Optional[Union[date, str]] = None,
date_fmt: Optional[str] = None,
) -> "SMTwo":
if not review_date:
review_date = date.today()

if not date_fmt:
date_fmt = year_mon_day
repetitions += 1

if isinstance(review_date, str):
review_date = datetime.strptime(review_date, date_fmt).date()
easiness += 0.1 - (5 - quality) * (0.08 + (5 - quality) * 0.02)
if easiness < 1.3:
easiness = 1.3

if quality < 3:
self.interval = 1
self.repetitions = 0
else:
if self.repetitions == 0:
self.interval = 1
elif self.repetitions == 1:
self.interval = 6
else:
self.interval = ceil(self.interval * self.easiness)
review_datetime += timedelta(days=interval)

self.repetitions = self.repetitions + 1
return {
"easiness": easiness,
"interval": interval,
"repetitions": repetitions,
"review_date": str(review_datetime),
}

self.easiness += 0.1 - (5 - quality) * (0.08 + (5 - quality) * 0.02)
if self.easiness < 1.3:
self.easiness = 1.3

review_date += timedelta(days=self.interval)
self.review_date = review_date
def first_review(
quality: int,
review_datetime: Optional[Union[datetime, str]] = None,
) -> Dict:
if not review_datetime:
review_datetime = datetime.utcnow()

return self
return review(quality, 2.5, 0, 0, review_datetime)
Loading

0 comments on commit d615f6e

Please sign in to comment.