Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
2f8a5c7
mutation testing mmachinery
pomponchik Feb 24, 2024
61e0d8b
some dunders
pomponchik Jun 17, 2024
603e8c0
issue templates
Apr 12, 2025
a203b04
added python 3.13 and deleted python 3.7 support in the CI
Apr 12, 2025
2c52515
new versions of dev deps
Apr 12, 2025
b26c02e
classifiers
Apr 12, 2025
5511ee4
deleted all AST-related things from the code
Apr 12, 2025
f71c0ee
no extra imports
Apr 12, 2025
e565a9b
import Protocol only from the standard library
Apr 12, 2025
1b0fe86
fix lint issues
Apr 12, 2025
6d3a776
fix lint issues
Apr 12, 2025
cbb6409
fix lint issues
Apr 12, 2025
5181610
fix lint issues
Apr 12, 2025
1750e81
fix lint issues
Apr 12, 2025
11e64ac
1 more assert in a test
Apr 12, 2025
c489760
more asserts
Apr 12, 2025
f29319e
more test coverage
Apr 12, 2025
59354ff
bugfix for the .startswith() method
Apr 12, 2025
90fb8f5
bugfix for the .endswith() method
Apr 12, 2025
1c7cd53
more test checks
Apr 12, 2025
00bf2a2
more test-cases
Apr 12, 2025
90f74c6
the LoC badge in the readme
Apr 12, 2025
a75ea14
Update pytest and ruff to newer versions
Nov 27, 2025
ad97606
Configure Ruff linter with custom rules and single quote style
Nov 27, 2025
e03558d
Fix lazy string initialization and update tests for compatibility
Nov 27, 2025
3b415c5
Update workflow actions to latest versions
Nov 27, 2025
c357498
Remove lazy flag from ChainUnit creation in proxy module
Nov 27, 2025
eaf4ed0
Add full_match to development dependencies
Nov 27, 2025
9817298
Fix TypeError assertion for rindex with int input
Nov 27, 2025
2aa56db
Fix TypeError message in test_index
Nov 27, 2025
567f53b
One more test
Nov 27, 2025
8e9974a
Add pragma to suppress coverage warning for condition
Nov 27, 2025
d327b42
Add pragma: no cover to function return guard
Nov 27, 2025
0b33a5d
Update codecov badge to coveralls badge
Nov 27, 2025
44de57d
Mark removeprefix and removesuffix as covered by pragma no cover
Nov 27, 2025
87653e5
Add Python 3.14 to classifiers
Nov 27, 2025
4975186
Enable debug print in test_init.py
Nov 27, 2025
acfd001
Add test_logging with skip marker
Nov 27, 2025
4abb249
Add logging file content print to test
Nov 27, 2025
30ccb9a
Fix test_logging to read and print log file content
Nov 27, 2025
b0a927f
Add file logging handler to test_logging_to_file
Nov 27, 2025
02a9c75
Add debug prints to track handler state during test_logging_to_file
Nov 27, 2025
3f0c387
Use temporary directory for logging file tests
Nov 28, 2025
186e176
Remove try-except block for os.remove in test_logging_to_file
Nov 28, 2025
eb63e6c
Refactor logging handler addition to use variable assignment
Nov 28, 2025
7070d53
Fix file cleanup in test_logging_to_file
Nov 28, 2025
5f6561f
Remove test_logging_to_file function from tests
Nov 28, 2025
42ff62f
Remove unused `os` import
Nov 28, 2025
8a826ca
Add Python 3.14 and 3.14t to test matrix
Nov 28, 2025
8a14907
New version tag
Nov 28, 2025
3617373
Set up Python using actions/setup-python@v5
Nov 28, 2025
dc1fdbf
Update test workflow to use Coveralls and cache pip dependencies
Nov 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: pomponchik

---

## Short description

Replace this text with a short description of the error and the behavior that you expected to see instead.


## Describe the bug in detail

Please add this test in such a way that it reproduces the bug you found and does not pass:

```python
def test_your_bug():
...
```

Writing the test, please keep compatibility with the [`pytest`](https://docs.pytest.org/) framework.

If for some reason you cannot describe the error in the test format, describe here the steps to reproduce it.


## Environment
- OS: ...
- Python version (the output of the `python --version` command): ...
- Version of this package: ...
26 changes: 26 additions & 0 deletions .github/ISSUE_TEMPLATE/documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: Documentation fix
about: Add something to the documentation, delete it, or change it
title: ''
labels: documentation
assignees: pomponchik
---

## It's cool that you're here!

Documentation is an important part of the project, we strive to make it high-quality and keep it up to date. Please adjust this template by outlining your proposal.


## Type of action

What do you want to do: remove something, add it, or change it?


## Where?

Specify which part of the documentation you want to make a change to? For example, the name of an existing documentation section or the line number in a file `README.md`.


## The essence

Please describe the essence of the proposed change
17 changes: 17 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: pomponchik

---

## Short description

What do you propose and why do you consider it important?


## Some details

If you can, provide code examples that will show how your proposal will work. Also, if you can, indicate which alternatives to this behavior you have considered. And finally, how do you propose to test the correctness of the implementation of your idea, if at all possible?
12 changes: 12 additions & 0 deletions .github/ISSUE_TEMPLATE/question.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
name: Question or consultation
about: Ask anything about this project
title: ''
labels: guestion
assignees: pomponchik

---

## Your question

Here you can freely describe your question about the project. Please, before doing this, read the documentation provided, and ask the question only if the necessary answer is not there. In addition, please keep in mind that this is a free non-commercial project and user support is optional for its author. The response time is not guaranteed in any way.
16 changes: 12 additions & 4 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.7']
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14', '3.14t']

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

Expand All @@ -25,8 +25,16 @@ jobs:

- name: Run ruff
shell: bash
run: ruff f
run: ruff check f

- name: Run mypy
shell: bash
run: mypy f --strict

- name: Run mypy for tests
shell: bash
run: mypy tests

- name: Run ruff for tests
shell: bash
run: ruff check tests
8 changes: 3 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ jobs:
# IMPORTANT: this permission is mandatory for trusted publishing
id-token: write
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Set up Python
uses: actions/setup-python@v5

- name: Install dependencies
shell: bash
Expand Down
70 changes: 42 additions & 28 deletions .github/workflows/tests_and_coverage.yml
Original file line number Diff line number Diff line change
@@ -1,41 +1,55 @@
name: Tests

on:
push
on: push

jobs:
build:

runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12']
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install the library
shell: bash
run: pip install .

- name: Install dependencies
shell: bash
run: pip install -r requirements_dev.txt

- name: Run tests and show coverage on the command line
run: coverage run --source=f --omit="*tests*" -m pytest --cache-clear && coverage report -m

- name: Upload reports to codecov
env:
CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}}
if: runner.os == 'Linux'
run: |
curl -Os https://uploader.codecov.io/latest/linux/codecov
find . -iregex "codecov.*"
chmod +x codecov
./codecov -t ${CODECOV_TOKEN}
- name: Install the library
shell: bash
run: pip install .

- name: Cache pip dependencies
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ github.workflow }}-${{ hashFiles('requirements_dev.txt') }}
restore-keys: |
${{ runner.os }}-pip-${{ github.workflow }}-

- name: Install dependencies
shell: bash
run: pip install -r requirements_dev.txt

- name: Print all libs
shell: bash
run: pip list

- name: Run tests and show coverage on the command line
run: |
coverage run --source=f --omit="*tests*" -m pytest --cache-clear --assert=plain && coverage report -m --fail-under=100
coverage xml

- name: Upload coverage to Coveralls
if: runner.os == 'Linux'
env:
COVERALLS_REPO_TOKEN: ${{secrets.COVERALLS_REPO_TOKEN}}
uses: coverallsapp/github-action@v2
with:
format: cobertura
file: coverage.xml

- name: Run tests and show the branch coverage on the command line
run: coverage run --branch --source=f --omit="*tests*" -m pytest --cache-clear --assert=plain && coverage report -m --fail-under=100
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ build
.mypy_cache
.ruff_cache
test.py
.mutmut-cache
html
1 change: 0 additions & 1 deletion .ruff.toml

This file was deleted.

3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

[![Downloads](https://static.pepy.tech/badge/fazy/month)](https://pepy.tech/project/fazy)
[![Downloads](https://static.pepy.tech/badge/fazy)](https://pepy.tech/project/fazy)
[![codecov](https://codecov.io/gh/pomponchik/fazy/branch/main/graph/badge.svg)](https://codecov.io/gh/pomponchik/fazy)
[![Coverage Status](https://coveralls.io/repos/github/pomponchik/fazy/badge.svg?branch=main)](https://coveralls.io/github/pomponchik/fazy?branch=main)
[![Lines of code](https://sloc.xyz/github/pomponchik/fazy/?category=code)](https://github.com/boyter/scc/)
[![Hits-of-Code](https://hitsofcode.com/github/pomponchik/fazy?branch=main)](https://hitsofcode.com/github/pomponchik/fazy/view?branch=main)
[![Tests](https://github.com/pomponchik/fazy/actions/workflows/tests_and_coverage.yml/badge.svg)](https://github.com/pomponchik/fazy/actions/workflows/tests_and_coverage.yml)
[![PyPI version](https://badge.fury.io/py/fazy.svg)](https://badge.fury.io/py/fazy)
Expand Down
2 changes: 1 addition & 1 deletion f/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
from f.proxy_module import ProxyModule as ProxyModule

from f.proxy_module import ProxyModule as ProxyModule

sys.modules[__name__].__class__ = ProxyModule
2 changes: 1 addition & 1 deletion f/chain_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


class ChainUnit:
def __init__(self, base: str, appendix: Optional[str] = None, lazy: bool = True) -> None:
def __init__(self, base: str, appendix: Optional[str] = None) -> None:
self.base = base
self.appendix = appendix
if self.appendix is not None:
Expand Down
20 changes: 10 additions & 10 deletions f/lazy_string.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from collections import UserString
from typing import Union, List, Dict, Tuple, Iterable, Callable, Optional, Any
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union

from f.chain_unit import ChainUnit


class LazyString(UserString, str): # type: ignore[misc]
__slots__ = ('units', 'local_locals', 'local_globals', 'local_nonlocals', 'lazy', 'result')
__slots__ = ('lazy', 'local_globals', 'local_locals', 'local_nonlocals', 'result', 'units')

def __init__(self, units: List[ChainUnit], local_locals: Dict[str, Any], local_globals: Dict[str, Any], local_nonlocals: Dict[str, Any], lazy: bool) -> None:
self.units: List[ChainUnit] = units
Expand All @@ -15,7 +15,7 @@ def __init__(self, units: List[ChainUnit], local_locals: Dict[str, Any], local_g
self.lazy: bool = lazy
self.result: Optional[str] = None

def __new__(cls, *args: Any, **kwargs: Any) -> 'LazyString':
def __new__(cls, *args: Any, **kwargs: Any) -> 'LazyString': # noqa: ARG004
return str.__new__(cls)

def __add__(self, other: Union['LazyString', str]) -> str:
Expand Down Expand Up @@ -57,7 +57,7 @@ def __reduce__(self) -> Union[str, Tuple[Callable[[], Any], Tuple[Any, ...], Ite
def __setattr__(self, name: str, value: Any) -> None:
if name not in type(self).__slots__:
raise AttributeError(
"'{0}' object has no attribute '{1}'".format(type(self).__name__, name)
"'{0}' object has no attribute '{1}'".format(type(self).__name__, name),
)
object.__setattr__(self, name, value)

Expand Down Expand Up @@ -97,14 +97,14 @@ def startswith(self, prefix: Union['LazyString', str, Tuple[Union['LazyString',
if isinstance(prefix, type(self)):
prefix = prefix.data
elif isinstance(prefix, tuple):
prefix = tuple(*(x.data if isinstance(x, type(self)) else x for x in prefix))
prefix = tuple((x.data if isinstance(x, type(self)) else x for x in prefix))
return self.data.startswith(prefix, *other_args)

def endswith(self, suffix: Union['LazyString', str, Tuple[Union['LazyString', str], ...]], *other_args: int) -> bool:
if isinstance(suffix, type(self)):
suffix = suffix.data
elif isinstance(suffix, tuple):
suffix = tuple(*(x.data if isinstance(x, type(self)) else x for x in suffix))
suffix = tuple((x.data if isinstance(x, type(self)) else x for x in suffix))
return self.data.endswith(suffix, *other_args)

def index(self, sub: Union['LazyString', str], *other: int) -> int:
Expand Down Expand Up @@ -134,12 +134,12 @@ def casefold(self) -> str:
def expandtabs(self, tabsize: int = 8) -> str:
return self.data.expandtabs(tabsize)

def removeprefix(self, prefix: Union['LazyString', str]) -> str:
def removeprefix(self, prefix: Union['LazyString', str]) -> str: # pragma: no cover
if isinstance(prefix, type(self)):
prefix = prefix.data
return self.data.removeprefix(prefix) # type: ignore[attr-defined, no-any-return, unused-ignore]

def removesuffix(self, suffix: Union['LazyString', str]) -> str:
def removesuffix(self, suffix: Union['LazyString', str]) -> str: # pragma: no cover
if isinstance(suffix, type(self)):
suffix = suffix.data
return self.data.removesuffix(suffix) # type: ignore[attr-defined, no-any-return, unused-ignore]
Expand Down Expand Up @@ -176,8 +176,8 @@ def maketrans(x: Union[Dict[Union[int, str, UserString], Optional[Union[int, str

first_item = {}
for key, value in x.items():
key = key.data if isinstance(key, UserString) else key
value = value.data if isinstance(value, UserString) else value
key = key.data if isinstance(key, UserString) else key # noqa: PLW2901
value = value.data if isinstance(value, UserString) else value # noqa: PLW2901
first_item[key] = value

return str.maketrans(first_item, *converted_others) # type: ignore[arg-type]
Expand Down
Loading
Loading