├── app ├── __init__.py ├── test_main.py └── main.py ├── tests ├── __init__.py └── test_tests.py ├── .gitignore ├── requirements.txt ├── .flake8 ├── README.md └── .github └── workflows └── test.yml /app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/test_main.py: -------------------------------------------------------------------------------- 1 | from app.main import is_isogram 2 | 3 | # write your code here 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | *.iml 4 | .env 5 | .DS_Store 6 | venv/ 7 | .pytest_cache/ 8 | **__pycache__/ 9 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pytest==6.2.5 2 | flake8==5.0.4 3 | flake8-annotations==2.9.1 4 | flake8-quotes==3.3.1 5 | flake8-variables-names==0.0.5 6 | pep8-naming==0.13.2 7 | pytest-xdist==2.5.0 8 | -------------------------------------------------------------------------------- /app/main.py: -------------------------------------------------------------------------------- 1 | def is_isogram(word: str) -> bool: 2 | word_lower = word.lower() 3 | for letter in word_lower: 4 | if word_lower.count(letter) > 1: 5 | return False 6 | return True 7 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | inline-quotes = " 3 | ignore = E203, E266, W503, ANN002, ANN003, ANN101, ANN102, ANN401, N807, N818 4 | max-line-length = 79 5 | max-complexity = 18 6 | select = B,C,E,F,W,T4,B9,ANN,Q0,N8,VNE 7 | exclude = venv, tests 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Is isogram 2 | 3 | Read [the guideline](https://github.com/mate-academy/py-task-guideline/blob/main/README.md) before start. 4 | 5 | An isogram is a word that has no repeating letters, consecutive or non-consecutive. 6 | 7 | Inside `app/test_main.py`, write tests for a function `is_isogram` that takes a string word, that contains only letters, 8 | and checks whether this word is an isogram. 9 | 10 | Notes: 11 | 12 | - for this task, the empty string is an isogram; 13 | - function should be case-insensitive (M and m are considered the same letter). 14 | 15 | **Please note:** you have to use `pytest` for writing tests. 16 | 17 | Examples: 18 | ```python 19 | is_isogram('playgrounds') is True 20 | is_isogram('look') is False 21 | is_isogram('Adam') is False 22 | is_isogram('') is True 23 | ``` 24 | 25 | Run `pytest app/` to check if function pass your tests. 26 | 27 | Run `pytest --numprocesses=auto tests/` to check if your tests cover all boundary conditions 28 | and pass task tests. 29 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push, pull_request_target] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout repo 11 | uses: actions/checkout@v2 12 | with: 13 | ref: ${{github.event.pull_request.head.ref}} 14 | repository: ${{github.event.pull_request.head.repo.full_name}} 15 | 16 | - name: Set Up Python 3.10 17 | uses: actions/setup-python@v2 18 | with: 19 | python-version: "3.10" 20 | 21 | - name: Install pytest and flake8 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install -r requirements.txt 25 | 26 | - name: Run flake8 27 | run: flake8 app/ 28 | - name: Run student tests 29 | timeout-minutes: 5 30 | run: pytest app/ 31 | - name: Run mentor tests 32 | timeout-minutes: 5 33 | run: pytest --numprocesses=auto tests/ 34 | - uses: mate-academy/auto-approve-action@v2 35 | if: ${{ github.event.pull_request && success() }} 36 | with: 37 | github-token: ${{ github.token }} 38 | - uses: mate-academy/auto-reject-action@v2 39 | if: ${{ github.event.pull_request && failure() }} 40 | with: 41 | github-token: ${{ github.token }} 42 | -------------------------------------------------------------------------------- /tests/test_tests.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from app import main 4 | 5 | 6 | def test_isogram_is_case_insensitive(monkeypatch): 7 | def case_sensitive_isogram(word: str): 8 | for letter in word: 9 | if word.count(letter) > 1: 10 | return False 11 | return True 12 | 13 | monkeypatch.setattr(main, "is_isogram", case_sensitive_isogram) 14 | 15 | test_result = pytest.main(["app/test_main.py"]) 16 | assert test_result.value == 1, ( 17 | "String with different cases of the same letter is not an isogram." 18 | ) 19 | 20 | 21 | def test_empty_string_is_isogram(monkeypatch): 22 | def non_empty_string_isogram(word: str): 23 | if word == "": 24 | return False 25 | word_lower = word.lower() 26 | for letter in word_lower: 27 | if word_lower.count(letter) > 1: 28 | return False 29 | return True 30 | 31 | monkeypatch.setattr(main, "is_isogram", non_empty_string_isogram) 32 | 33 | test_result = pytest.main(["app/test_main.py"]) 34 | assert test_result.value == 1, ( 35 | "Empty string is an isogram." 36 | ) 37 | 38 | 39 | def test_non_consecutive_letters_are_not_isogram(monkeypatch): 40 | def only_consecutive_letters_are_not_isogram(word): 41 | word_lower = word.lower() 42 | for ind in range(len(word_lower) - 1): 43 | if word_lower[ind] == word_lower[ind + 1]: 44 | return False 45 | return True 46 | 47 | monkeypatch.setattr( 48 | main, "is_isogram", only_consecutive_letters_are_not_isogram 49 | ) 50 | 51 | test_result = pytest.main(["app/test_main.py"]) 52 | assert test_result.value == 1, ( 53 | "Not only consecutive letters are not an isogram." 54 | ) 55 | 56 | 57 | def test_consecutive_letters_are_not_isogram(monkeypatch): 58 | def only_non_consecutive_letters_are_not_isogram(word): 59 | word_lower = word.lower() 60 | for ind in range(1, len(word_lower) - 1): 61 | if (word_lower.count(word_lower[ind]) >= 2 and 62 | not (word_lower[ind] == word_lower[ind + 1] or 63 | word_lower[ind] == word_lower[ind - 1])): 64 | return False 65 | return True 66 | 67 | monkeypatch.setattr( 68 | main, "is_isogram", only_non_consecutive_letters_are_not_isogram 69 | ) 70 | 71 | test_result = pytest.main(["app/test_main.py"]) 72 | assert test_result.value == 1, ( 73 | "Not only non-consecutive letters are not an isogram." 74 | ) 75 | --------------------------------------------------------------------------------