Full Code of cansarigol/pdbr for AI

master a85df2d320fd cached
37 files
59.0 KB
15.8k tokens
81 symbols
1 requests
Download .txt
Repository: cansarigol/pdbr
Branch: master
Commit: a85df2d320fd
Files: 37
Total size: 59.0 KB

Directory structure:
gitextract_rmp4r7u5/

├── .github/
│   └── workflows/
│       ├── release.yml
│       └── tests.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .vscode/
│   └── settings.json
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── noxfile.py
├── pdbr/
│   ├── __init__.py
│   ├── __main__.py
│   ├── _cm.py
│   ├── _console_layout.py
│   ├── _pdbr.py
│   ├── cli.py
│   ├── helpers.py
│   ├── middlewares/
│   │   ├── __init__.py
│   │   ├── django.py
│   │   └── starlette.py
│   ├── runner.py
│   └── utils.py
├── pyproject.toml
├── runtests.py
├── scripts/
│   ├── lint
│   └── test
├── setup.cfg
└── tests/
    ├── __init__.py
    ├── conftest.py
    ├── test_api.py
    ├── test_config.py
    ├── test_magic.py
    ├── test_pdbr.py
    └── tests_django/
        ├── __init__.py
        ├── test_settings.py
        ├── tests.py
        └── urls.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  push:
    tags:
      - '*'
  workflow_dispatch:

jobs:
  build-n-publish:
    name: Build and publish to PyPI
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python 3.10.16
      uses: actions/setup-python@v4
      with:
        python-version: '3.10.16'
    - name: Install poetry
      run: python -m pip install poetry --user
    - name: Build
      run: poetry build
    - name: Publish to PyPI
      env:
        POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_PASSWORD }}
      run: poetry publish


================================================
FILE: .github/workflows/tests.yml
================================================
name: Test

on:
  push:
    branches: ["master"]
  pull_request:
    branches: ["master"]

jobs:
  check:
    name: "Check"
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v4
        with:
          python-version: '3.10'
      - name: Install pre-commit
        run: |
          pip install --upgrade pre-commit
      - name: Run check
        run: |
          pre-commit run --all-files

  test:
    name: "Tests"
    runs-on: ${{ matrix.platform }}
    needs: check

    strategy:
      matrix:
        platform: [ubuntu-latest, macos-latest, windows-latest]
        python-version: ["3.8", "3.9", "3.10", "3.11"]

    steps:
      - uses: actions/checkout@v4

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

      - name: Install nox
        run: |
          pip install --upgrade nox
      - name: Run tests
        run: |
          nox --sessions test django_test


================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
#   For a library or package, you might want to ignore these files since the code is
#   intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# lint
.ruff_cache


================================================
FILE: .pre-commit-config.yaml
================================================
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: check-added-large-files
      - id: check-case-conflict
      - id: check-merge-conflict
      - id: check-symlinks
      - id: check-toml
      - id: end-of-file-fixer
      - id: trailing-whitespace
  - repo: https://github.com/pre-commit/pygrep-hooks
    rev: v1.10.0
    hooks:
      - id: python-check-blanket-noqa
      - id: python-use-type-annotations
  - repo: https://github.com/jendrikseipp/vulture
    rev: v2.14
    hooks:
      - id: vulture
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: 'v0.9.3'
    hooks:
      - id: ruff
  - repo: https://github.com/psf/black
    rev: 24.10.0
    hooks:
      - id: black
        language_version: python3


================================================
FILE: .vscode/settings.json
================================================
{
    "makefile.extensionOutputFolder": "./.vscode"
}


================================================
FILE: Dockerfile
================================================
FROM python:3.7.9

ENV PYTHONUNBUFFERED=0

RUN pip install pip \
 && pip install nox \
 && pip install pre-commit

WORKDIR /pdbr
COPY . .

RUN pre-commit run --all-files
RUN nox --sessions test django_test


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 Can Sarıgöl

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Makefile
================================================
lint:
	sh scripts/lint

test:
	sh scripts/test

celery:
	celery -A tasks worker --loglevel=info

build:
	docker build -t pdbr .

act:
	act -r -j test --container-architecture linux/amd64


================================================
FILE: README.md
================================================
# pdbr

[![PyPI version](https://badge.fury.io/py/pdbr.svg)](https://pypi.org/project/pdbr/) [![Python Version](https://img.shields.io/pypi/pyversions/pdbr.svg)](https://pypi.org/project/pdbr/) [![](https://github.com/cansarigol/pdbr/workflows/Test/badge.svg)](https://github.com/cansarigol/pdbr/actions?query=workflow%3ATest) [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/cansarigol/pdbr/master.svg)](https://results.pre-commit.ci/latest/github/cansarigol/pdbr/master)


`pdbr` is intended to make the PDB results more colorful. it uses [Rich](https://github.com/willmcgugan/rich) library to carry out that.


## Installing

Install with `pip` or your favorite PyPi package manager.

```
pip install pdbr
```


## Breakpoint

In order to use ```breakpoint()```, set **PYTHONBREAKPOINT** with "pdbr.set_trace"

```python
import os

os.environ["PYTHONBREAKPOINT"] = "pdbr.set_trace"
```

or just import pdbr

```python
import pdbr
```

## New commands
### (i)nspect / inspectall | ia
[rich.inspect](https://rich.readthedocs.io/en/latest/introduction.html?s=03#rich-inspector)
### search | src
Search a phrase in the current frame.
In order to repeat the last one, type **/** character as arg.
### sql
Display value in sql format. Don't forget to install [sqlparse](https://github.com/andialbrecht/sqlparse) package.
![](/images/image13.png)

It can be used for Django model queries as follows.
```
>>> sql str(Users.objects.all().query)
```
![](/images/image14.png)
### (syn)tax
[ val,lexer ] Display [lexer](https://pygments.org/docs/lexers/).
### (v)ars
Get the local variables list as table.
### varstree | vt
Get the local variables list as tree.

![](/images/image5.png)

## Config
Config is specified in **setup.cfg** and can be local or global. Local config (current working directory) has precedence over global (default) one. Global config must be located at `$XDG_CONFIG_HOME/pdbr/setup.cfg`.

### Style
In order to use Rich's traceback, style, and theme:

```
[pdbr]
style = yellow
use_traceback = True
theme = friendly
```

Also custom `Console` object can be assigned to the `set_trace`.
```python
import pdbr

from rich.console import Console
from rich.style import Style
from rich.theme import Theme

custom_theme = Theme({
    "info": "dim cyan",
    "warning": "magenta",
    "danger": "bold red",
})
custom_style = Style(
    color="magenta",
    bgcolor="yellow",
    italic=True,
)
console = Console(theme=custom_theme, style=custom_style)

pdbr.set_trace(console=console)
```
### History
**store_history** setting is used to keep and reload history, even the prompt is closed and opened again:
```
[pdbr]
...
store_history=.pdbr_history
```

By default, history is stored globally in `~/.pdbr_history`.

### Context
The **context** setting is used to specify the number of lines of source code context to show when displaying stacktrace information.
```
[pdbr]
...
context=10
```
This setting is only available when using `pdbr` with `IPython`.

## Celery
In order to use **Celery** remote debugger with pdbr, use ```celery_set_trace``` as below sample. For more information see the [Celery user guide](https://docs.celeryproject.org/en/stable/userguide/debugging.html).

```python
from celery import Celery

app = Celery('tasks', broker='pyamqp://guest@localhost//')

@app.task
def add(x, y):

    import pdbr; pdbr.celery_set_trace()

    return x + y

```
#### Telnet
Instead of using `telnet` or `nc`, in terms of using pdbr style, `pdbr_telnet` command can be used.
![](/images/image6.png)

Also in order to activate history and be able to use arrow keys, install and use [rlwrap](https://github.com/hanslub42/rlwrap) package.

```
rlwrap -H '~/.pdbr_history' pdbr_telnet localhost 6899
```

## IPython

`pdbr` integrates with [IPython](https://ipython.readthedocs.io/).

This makes [`%magics`](https://ipython.readthedocs.io/en/stable/interactive/magics.html) available, for example:

```python
(Pdbr) %timeit range(100)
104 ns ± 2.05 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
```

To enable `IPython` features, install it separately, or like below:

```
pip install pdbr[ipython]
```

## pytest
In order to use `pdbr` with pytest `--pdb` flag, add `addopts` setting in your pytest.ini.

```
[pytest]
addopts: --pdbcls=pdbr:RichPdb
```

## sys.excepthook
The `sys.excepthook` is a Python system hook that provides a way to customize the behavior when an unhandled exception occurs. Since `pdbr` use  automatic traceback handler feature of `rich`, formatting exception print is not necessary if `pdbr` module is already imported.

In order to use post-mortem or perform other debugging features of `pdbr`,  override `sys.excepthook` with a function that will act as your custom excepthook:
```python
import sys
import pdbr

def custom_excepthook(exc_type, exc_value, exc_traceback):
    pdbr.post_mortem(exc_traceback, exc_value)

    # [Optional] call the original excepthook as well
    sys.__excepthook__(exc_type, exc_value, exc_traceback)

sys.excepthook = custom_excepthook
```
Now, whenever an unhandled exception occurs, `pdbr` will be triggered, allowing you to debug the issue interactively.

## Context Decorator
`pdbr_context` and `apdbr_context` (`asyncio` corresponding) can be used as **with statement** or **decorator**. It calls `post_mortem` if `traceback` is not none.

```python
from pdbr import apdbr_context, pdbr_context

@pdbr_context()
def foo():
    ...

def bar():
    with pdbr_context():
        ...


@apdbr_context()
async def foo():
    ...

async def bar():
    async with apdbr_context():
        ...
```

![](/images/image12.png)
## Django DiscoverRunner
To being activated the pdb in Django test, change `TEST_RUNNER` like below. Unlike Django (since you are not allowed to use for smaller versions than 3), pdbr runner can be used for version 1.8 and subsequent versions.

```
TEST_RUNNER = "pdbr.runner.PdbrDiscoverRunner"
```
![](/images/image10.png)
## Middlewares
### Starlette
```python
from fastapi import FastAPI
from pdbr.middlewares.starlette import PdbrMiddleware

app = FastAPI()

app.add_middleware(PdbrMiddleware, debug=True)


@app.get("/")
async def main():
    1 / 0
    return {"message": "Hello World"}
```
### Django
In order to catch the problematic codes with post mortem, place the middleware class.

```
MIDDLEWARE = (
    ...
    "pdbr.middlewares.django.PdbrMiddleware",
)
```
![](/images/image11.png)
## Shell
Running `pdbr` command in terminal starts an `IPython` terminal app instance. Unlike default `TerminalInteractiveShell`, the new shell uses pdbr as debugger class instead of `ipdb`.
#### %debug magic sample
![](/images/image9.png)
### As a Script
If `pdbr` command is used with an argument, it is invoked as a script and [debugger-commands](https://docs.python.org/3/library/pdb.html#debugger-commands) can be used with it.
```python
# equivalent code: `python -m pdbr -c 'b 5' my_test.py`
pdbr -c 'b 5' my_test.py

>>> Breakpoint 1 at /my_test.py:5
> /my_test.py(3)<module>()
      1
      2
----> 3 def test():
      4         foo = "foo"
1     5         bar = "bar"

(Pdbr)

```
### Terminal
#### Django shell sample
![](/images/image7.png)

## Vscode user snippet

To create or edit your own snippets, select **User Snippets** under **File > Preferences** (**Code > Preferences** on macOS), and then select **python.json**.

Place the below snippet in json file for **pdbr**.

```
{
  ...
  "pdbr": {
        "prefix": "pdbr",
        "body": "import pdbr; pdbr.set_trace()",
        "description": "Code snippet for pdbr debug"
    },
}
```

For **Celery** debug.

```
{
  ...
  "rdbr": {
        "prefix": "rdbr",
        "body": "import pdbr; pdbr.celery_set_trace()",
        "description": "Code snippet for Celery pdbr debug"
    },
}
```

## Samples
![](/images/image1.png)

![](/images/image3.png)

![](/images/image4.png)

### Traceback
![](/images/image2.png)


================================================
FILE: noxfile.py
================================================
import nox

nox.options.stop_on_first_error = True


@nox.session
def test(session, reuse_venv=True):
    session.install(
        ".",
        "pytest",
        "pytest-cov",
        "rich",
        "prompt_toolkit",
        "IPython",
    )
    session.run(
        "pytest",
        "--cov-report",
        "term-missing",
        "--cov=pdbr",
        "--capture=no",
        "--disable-warnings",
        "tests",
    )


@nox.session
@nox.parametrize("django", ["3.2", "4.2"])
def django_test(session, django, reuse_venv=True):
    session.install(f"django=={django}", "rich", "pytest")
    session.run("python", "runtests.py")


================================================
FILE: pdbr/__init__.py
================================================
from pdbr.__main__ import RichPdb, celery_set_trace, pm, post_mortem, run, set_trace
from pdbr._cm import apdbr_context, pdbr_context

__all__ = [
    "set_trace",
    "run",
    "pm",
    "post_mortem",
    "celery_set_trace",
    "RichPdb",
    "pdbr_context",
    "apdbr_context",
]


================================================
FILE: pdbr/__main__.py
================================================
import os
import pdb
import sys

from .utils import _pdbr_cls, _rdbr_cls

os.environ["PYTHONBREAKPOINT"] = "pdbr.set_trace"

RichPdb = _pdbr_cls(return_instance=False, show_layouts=False)


def set_trace(*, console=None, header=None, context=None, show_layouts=False):
    pdb_cls = _pdbr_cls(console=console, context=context, show_layouts=show_layouts)
    if header is not None:
        pdb_cls.message(header)
    pdb_cls.set_trace(sys._getframe().f_back)


def run(statement, globals=None, locals=None):
    RichPdb().run(statement, globals, locals)


def post_mortem(traceback=None, value=None):
    _, sys_value, sys_traceback = sys.exc_info()
    value = value or sys_value
    traceback = traceback or sys_traceback

    if traceback is None:
        raise ValueError(
            "A valid traceback must be passed if no exception is being handled"
        )

    p = RichPdb()
    p.reset()
    if value:
        p.error(value)
    p.interaction(None, traceback)


def pm():
    post_mortem(sys.last_traceback)


def celery_set_trace(frame=None):
    pdb_cls = _rdbr_cls()
    if frame is None:
        frame = sys._getframe().f_back
    return pdb_cls.set_trace(frame)


def main():
    pdb.Pdb = RichPdb
    pdb.main()


if __name__ == "__main__":
    main()


================================================
FILE: pdbr/_cm.py
================================================
from contextlib import ContextDecorator
from functools import wraps

from pdbr.__main__ import post_mortem


class pdbr_context(ContextDecorator):
    def __init__(self, suppress_exc=True, debug=True):
        self.suppress_exc = suppress_exc
        self.debug = debug

    def __enter__(self):
        return self

    def __exit__(self, _, exc_value, exc_traceback):
        if exc_traceback and self.debug:
            post_mortem(exc_traceback, exc_value)
            return self.suppress_exc
        return False


class AsyncContextDecorator(ContextDecorator):
    def __call__(self, func):
        @wraps(func)
        async def inner(*args, **kwds):
            async with self._recreate_cm():
                return await func(*args, **kwds)

        return inner


class apdbr_context(AsyncContextDecorator):
    def __init__(self, suppress_exc=True, debug=True):
        self.suppress_exc = suppress_exc
        self.debug = debug

    async def __aenter__(self):
        return self

    async def __aexit__(self, _, exc_value, exc_traceback):
        if exc_traceback and self.debug:
            post_mortem(exc_traceback, exc_value)
            return self.suppress_exc
        return False


================================================
FILE: pdbr/_console_layout.py
================================================
from rich.containers import Lines
from rich.errors import NotRenderableError
from rich.layout import Layout
from rich.panel import Panel


class ConsoleLayoutMeta(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            instance = super().__call__(*args, **kwargs)
            cls._instances[cls] = instance
        return cls._instances[cls]


class ConsoleLayout(metaclass=ConsoleLayoutMeta):
    def __init__(self, console):
        self.console = console
        self.layout = self._prep_layout()

    def _prep_layout(self):
        layout = Layout()
        right_body = Layout(name="right_body", ratio=1)

        layout.split(
            Layout(name="left_body", ratio=2),
            right_body,
            splitter="row",
        )

        right_body.split(
            Layout(name="up_footer", ratio=2), Layout(name="bottom_footer", ratio=1)
        )
        return layout

    def print(self, message, code, stack_trace, vars, **kwargs):
        try:
            self.layout["left_body"].update(code)
            self.layout["up_footer"].update(Panel(vars, title="Locals"))

            self.layout["bottom_footer"].update(
                Panel(Lines(stack_trace), title="Stack", style="white on blue")
            )

            self.console.print(self.layout, **kwargs)
            self.console.print(message, **kwargs)
        except NotRenderableError:
            self.console.print(message, **kwargs)


================================================
FILE: pdbr/_pdbr.py
================================================
import inspect
import io
import re
from pathlib import Path
from pdb import Pdb

from rich import box, markup
from rich._inspect import Inspect
from rich.console import Console
from rich.panel import Panel
from rich.pretty import pprint
from rich.syntax import DEFAULT_THEME, Syntax
from rich.table import Table
from rich.text import Text
from rich.theme import Theme
from rich.tree import Tree

from pdbr._console_layout import ConsoleLayout

try:
    from IPython.terminal.interactiveshell import TerminalInteractiveShell

    TerminalInteractiveShell.simple_prompt = False
except ImportError:
    pass

WITHOUT_LAYOUT_COMMANDS = (
    "where",
    "w",
)
ANSI_ESCAPE = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")


class AsciiStdout(io.TextIOWrapper):
    pass


def rich_pdb_klass(
    base, is_celery=False, console=None, context=None, show_layouts=True
):
    class RichPdb(base):
        _style = None
        _theme = None
        _history_file = None
        _ipython_history_file = None
        _latest_search_arg = ""

        def __init__(
            self,
            completekey="tab",
            stdin=None,
            stdout=None,
            skip=None,
            nosigint=False,
            readrc=True,
        ):
            init_kwargs = (
                {"out": stdout}
                if is_celery
                else {
                    "completekey": completekey,
                    "stdin": stdin,
                    "stdout": stdout,
                    "skip": skip,
                    "nosigint": nosigint,
                    "readrc": readrc,
                }
            )
            if console is not None:
                self._console = console
            if context is not None:
                if base == Pdb:
                    raise ValueError("Context can only be used with IPython")
                init_kwargs["context"] = context
            super().__init__(**init_kwargs)

            self.prompt = "(Pdbr) "

        def pt_init(self, pt_session_options=None):
            from prompt_toolkit.history import FileHistory

            if self._ipython_history_file:
                history_file = FileHistory(self._ipython_history_file)
                self.shell.debugger_history = history_file
                # In order to fix the error for ipython 8.x
                self.debugger_history = history_file

            func = super().pt_init
            func_args = inspect.getfullargspec(super().pt_init).args
            if "pt_session_options" in func_args:
                func(pt_session_options)
            else:
                func()

        @property
        def console(self):
            if not hasattr(self, "_console"):
                self._console = Console(
                    file=(
                        AsciiStdout(buffer=self.stdout.buffer, encoding="ascii")
                        if is_celery
                        else self.stdout
                    ),
                    theme=Theme(
                        {"info": "dim cyan", "warning": "magenta", "danger": "bold red"}
                    ),
                    style=self._style,
                    force_terminal=True,
                    force_interactive=True,
                )
            return self._console

        def do_help(self, arg):
            super().do_help(arg)
            if not arg:
                self._print(
                    Panel(
                        "Visit "
                        "[bold][link=https://github.com/cansarigol/pdbr]"
                        "https://github.com/cansarigol/pdbr[/link][/]"
                        " for more!"
                    ),
                    style="warning",
                    print_layout=False,
                )

        do_help.__doc__ = base.do_help.__doc__
        do_h = do_help

        def _get_syntax_for_list(self, line_range=None):
            if not line_range:
                first = max(1, self.curframe.f_lineno - 5)
                line_range = first, first + 10
            filename = self.curframe.f_code.co_filename
            highlight_lines = {self.curframe.f_lineno}

            return Syntax.from_path(
                filename,
                line_numbers=True,
                theme=self._theme or DEFAULT_THEME,
                line_range=line_range,
                highlight_lines=highlight_lines,
            )

        def _get_variables(self):
            try:
                return [
                    (k, str(v), str(type(v)))
                    for k, v in self.curframe.f_locals.items()
                    if not k.startswith("__") and k != "pdbr"
                ]
            except AttributeError:
                return []

        def do_l(self, arg):
            """l
            List 11 lines source code for the current file.
            """
            try:
                self._print(self._get_syntax_for_list(), print_layout=False)
            except BaseException:
                self.error("could not get source code")

        def do_longlist(self, arg):
            """longlist | ll
            List the whole source code for the current function or frame.
            """
            try:
                lines, lineno = self._getsourcelines(self.curframe)
                last = lineno + len(lines)
                self._print(
                    self._get_syntax_for_list((lineno, last)), print_layout=False
                )
            except BaseException:
                self.error("could not get source code")

        do_ll = do_longlist

        def do_source(self, arg):
            """source expression
            Try to get source code for the given object and display it.
            """
            try:
                obj = self._getval(arg)
                lines, lineno = self._getsourcelines(obj)
                last = lineno + len(lines)
                self._print(
                    self._get_syntax_for_list((lineno, last)), print_layout=False
                )
            except BaseException as err:
                self.error(err)

        def do_search(self, arg):
            """search | src
            Search a phrase in the current frame.
            In order to repeat the last one, type `/` character as arg.
            """
            if not arg or (arg == "/" and not self._latest_search_arg):
                self.error("Search failed: arg is missing")
                return

            if arg == "/":
                arg = self._latest_search_arg
            else:
                self._latest_search_arg = arg

            lines, lineno = self._getsourcelines(self.curframe)
            indexes = [index for index, line in enumerate(lines, lineno) if arg in line]

            if len(indexes) > 0:
                bigger_indexes = [
                    index for index in indexes if index > self.curframe.f_lineno
                ]
                next_line = bigger_indexes[0] if bigger_indexes else indexes[0]
                return super().do_jump(next_line)
            else:
                self.error(f"Search failed: '{arg}' not found")

        do_src = do_search

        def _getsourcelines(self, obj):
            lines, lineno = inspect.getsourcelines(obj)
            lineno = max(1, lineno)
            return lines, lineno

        def get_varstable(self):
            variables = self._get_variables()
            if not variables:
                return
            table = Table(title="List of local variables", box=box.MINIMAL)

            table.add_column("Variable", style="cyan")
            table.add_column("Value", style="magenta")
            table.add_column("Type", style="green")
            [
                table.add_row(variable, value, _type)
                for variable, value, _type in variables
            ]
            return table

        def do_v(self, arg):
            """v(ars)
            List of local variables
            """
            self._print(self.get_varstable(), print_layout=False)

        def get_varstree(self):
            variables = self._get_variables()
            if not variables:
                return
            tree_key = ""
            type_tree = None
            tree = Tree("Variables")

            for variable, value, _type in sorted(
                variables, key=lambda item: (item[2], item[0])
            ):
                if tree_key != _type:
                    if tree_key != "":
                        tree.add(type_tree, style="bold green")
                    type_tree = Tree(_type)
                    tree_key = _type
                type_tree.add(f"{variable}: {value}", style="magenta")
            if type_tree:
                tree.add(type_tree, style="bold green")
            return tree

        def do_varstree(self, arg):
            """varstree | vt
            List of local variables in Rich.Tree
            """
            self._print(self.get_varstree(), print_layout=False)

        do_vt = do_varstree

        def do_inspect(self, arg, all=False):
            """(i)nspect
            Display the data / methods / docs for any Python object.
            """
            try:
                self._print(
                    Inspect(self._getval(arg), methods=True, all=all),
                    print_layout=False,
                )
            except BaseException:
                pass

        def do_inspectall(self, arg):
            """inspectall | ia
            Inspect with all to see all attributes.
            """
            self.do_inspect(arg, all=True)

        do_i = do_inspect
        do_ia = do_inspectall

        def do_pp(self, arg):
            """pp expression
            Rich pretty print.
            """
            try:
                pprint(self._getval(arg), console=self.console)
            except BaseException:
                pass

        def do_syntax(self, arg):
            """syn(tax)[ val,lexer ]
            Display lexer. https://pygments.org/docs/lexers/
            """
            try:
                val, lexer = arg.split(",")
                val = val.strip()
                lexer = lexer.strip()
                val = Syntax(
                    self._getval(val),
                    self._getval(lexer),
                    theme=self._theme or DEFAULT_THEME,
                )
                self._print(val)
            except BaseException:
                pass

        do_syn = do_syntax

        def do_sql(self, arg):
            """sql
            Display value in sql format.
            """
            try:
                import sqlparse

                val = sqlparse.format(
                    self._getval(arg), reindent=True, keyword_case="upper"
                )
                self._print(val)
            except ModuleNotFoundError as error:
                raise type(error)("Install sqlparse to see sql format.") from error

        def displayhook(self, obj):
            if obj is not None:
                self._print(obj if isinstance(obj, (dict, list)) else repr(obj))

        def error(self, msg):
            self._print(msg, prefix="***", style="danger", print_layout=False)

        def _format_stack_entry(self, frame_lineno):
            stack_entry = Pdb.format_stack_entry(self, frame_lineno, "\n")
            return stack_entry.replace(str(Path.cwd().absolute()), "")

        def stack_trace(self):
            stacks = []
            try:
                for frame_lineno in self.stack:
                    frame, _ = frame_lineno
                    if frame is self.curframe:
                        prefix = "-> "
                    else:
                        prefix = "  "

                    stack_entry = self._format_stack_entry(frame_lineno)
                    first_line, _ = stack_entry.splitlines()
                    text_body = Text(stack_entry)
                    text_prefix = Text(prefix)
                    text_body.stylize("bold", len(first_line), len(stack_entry))
                    text_prefix.stylize("bold")
                    stacks.append(Text.assemble(text_prefix, text_body))
            except KeyboardInterrupt:
                pass
            return reversed(stacks)

        def message(self, msg):
            "this is used by the upstream PDB class"
            self._print(msg)

        def precmd(self, line):
            # Python 3.13+: Ctrl-D comes as literal "EOF"
            if line is None or line == "EOF":
                return "continue"

            if line.endswith("??"):
                line = "pinfo2 " + line[:-2]
            elif line.endswith("?"):
                line = "pinfo " + line[:-1]
            elif line.startswith("%"):
                if line.startswith("%%"):
                    self.error(
                        "Cell magics (multiline) are not yet supported. "
                        "Use a single '%' instead."
                    )
                return self.run_magic(line[1:])

            return super().precmd(line)

        def _print(self, val, prefix=None, style=None, print_layout=True):
            if val == "--Return--":
                return

            if isinstance(val, str) and ("[0m" in val or "[/" in val):
                val = markup.render(val)

            kwargs = {"style": str(style)} if style else {}
            args = (prefix, val) if prefix else (val,)
            if (
                show_layouts
                and print_layout
                and self.lastcmd not in WITHOUT_LAYOUT_COMMANDS
            ):
                self._print_layout(*args, **kwargs)
            else:
                self.console.print(*args, **kwargs)

        def _print_layout(self, val, **kwargs):
            ConsoleLayout(self.console).print(
                val,
                code=self._get_syntax_for_list(),
                stack_trace=self.stack_trace(**kwargs),
                vars=self.get_varstree(),
                **kwargs,
            )

        def print_stack_entry(self, frame_lineno, prompt_prefix="\n-> "):
            def print_syntax(*args):
                # Remove color format.
                self._print(
                    Syntax(
                        ANSI_ESCAPE.sub("", self.format_stack_entry(*args)),
                        "python",
                        theme=self._theme or DEFAULT_THEME,
                    ),
                    print_layout=False,
                )

            if is_celery:
                Pdb.print_stack_entry(self, frame_lineno, prompt_prefix)
            elif base == Pdb:
                print_syntax(frame_lineno, prompt_prefix)
            else:
                print_syntax(frame_lineno, "")

                # vds: >>
                frame, lineno = frame_lineno
                filename = frame.f_code.co_filename
                self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
                # vds: <<

        def print_stack_trace(self, count):
            """
            Use pdb stack trace due to hide hidden frames
            IPython is not using traceback count (for only python3.14),
            """
            Pdb.print_stack_trace(self, count=count)

        def run_magic(self, line) -> str:
            """
            Parses the line and runs the appropriate magic function.
            Assumes that the line is without a leading '%'.
            """
            magic_name, arg, line = self.parseline(line)
            if hasattr(self, f"do_{magic_name}"):
                # We want to use do_{magic_name} methods if defined.
                # This is indeed the case with do_pdef, do_pdoc etc,
                # which are defined by our base class (IPython.core.debugger.Pdb).
                result = getattr(self, f"do_{magic_name}")(arg)
            else:
                magic_fn = self.shell.find_line_magic(magic_name)
                if not magic_fn:
                    self.error(f"Line Magic %{magic_name} not found")
                    return ""
                if magic_name in ("time", "timeit"):
                    result = magic_fn(
                        arg,
                        local_ns={**self.curframe_locals, **self.curframe.f_globals},
                    )
                else:
                    result = magic_fn(arg)
            if result:
                result = str(result)
                self._print(result)
            return ""

    return RichPdb


================================================
FILE: pdbr/cli.py
================================================
import sys
from telnetlib import Telnet

from rich.file_proxy import FileProxy

from pdbr.helpers import run_ipython_shell


def shell():
    import getopt

    _, args = getopt.getopt(sys.argv[1:], "mhc:", ["command="])

    if not args:
        run_ipython_shell()
    else:
        from pdbr.__main__ import main

        main()


def telnet():
    from pdbr.__main__ import RichPdb

    pdb_cls = RichPdb()
    if len(sys.argv) < 3:
        pdb_cls.error("Usage : pdbr_telnet hostname port")
        sys.exit()

    class MyTelnet(Telnet):
        def fill_rawq(self):
            """
            exactly the same with Telnet.fill_rawq,
            buffer size is just changed from 50 to 1024.
            """
            if self.irawq >= len(self.rawq):
                self.rawq = b""
                self.irawq = 0
            buf = self.sock.recv(1024)
            self.msg("recv %r", buf)
            self.eof = not buf
            self.rawq = self.rawq + buf

    console = pdb_cls.console
    sys.stdout = FileProxy(console, sys.stdout)
    sys.stderr = FileProxy(console, sys.stderr)
    try:
        host = sys.argv[1]
        port = int(sys.argv[2])
        with MyTelnet(host, port) as tn:
            tn.interact()
    except BaseException as e:
        pdb_cls.error(e)
        sys.exit()


================================================
FILE: pdbr/helpers.py
================================================
import sys

from pdbr.__main__ import RichPdb


def run_ipython_shell():
    try:
        from IPython.terminal.interactiveshell import TerminalInteractiveShell
        from IPython.terminal.ipapp import TerminalIPythonApp
        from prompt_toolkit.history import FileHistory
        from traitlets import Type

        TerminalInteractiveShell.simple_prompt = False
    except ModuleNotFoundError as error:
        raise type(error)(
            "In order to use pdbr shell, install IPython with pdbr[ipython]"
        ) from error

    class PdbrTerminalInteractiveShell(TerminalInteractiveShell):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)

            if RichPdb._ipython_history_file:
                self.debugger_history = FileHistory(RichPdb._ipython_history_file)

        @property
        def debugger_cls(self):
            return RichPdb

    class PdbrTerminalIPythonApp(TerminalIPythonApp):
        interactive_shell_class = Type(
            klass=object,  # use default_value otherwise which only allow subclasses.
            default_value=PdbrTerminalInteractiveShell,
            help=(
                "Class to use to instantiate the TerminalInteractiveShell object. "
                "Useful for custom Frontends"
            ),
        ).tag(config=True)

    app = PdbrTerminalIPythonApp.instance()
    app.initialize()
    sys.exit(app.start())


================================================
FILE: pdbr/middlewares/__init__.py
================================================


================================================
FILE: pdbr/middlewares/django.py
================================================
import sys

from django.conf import settings
from django.core.exceptions import MiddlewareNotUsed

from pdbr.__main__ import post_mortem


class PdbrMiddleware:
    def __init__(self, get_response):
        if not settings.DEBUG:
            raise MiddlewareNotUsed()
        self.get_response = get_response

    def __call__(self, request):
        return self.get_response(request)

    def process_exception(self, request, exception):  # noqa: F841
        post_mortem(sys.exc_info()[2])


================================================
FILE: pdbr/middlewares/starlette.py
================================================
from starlette.middleware.errors import ServerErrorMiddleware

from pdbr._cm import apdbr_context


class PdbrMiddleware(ServerErrorMiddleware):
    async def __call__(self, scope, receive, send) -> None:
        async with apdbr_context(suppress_exc=False, debug=self.debug):
            await super().__call__(scope, receive, send)


================================================
FILE: pdbr/runner.py
================================================
import unittest

from django.test.runner import DebugSQLTextTestResult, DiscoverRunner

from pdbr.__main__ import RichPdb, post_mortem


class PDBRDebugResult(unittest.TextTestResult):
    _pdbr = RichPdb()

    def addError(self, test, err):
        super().addError(test, err)
        self._print(test, err)

    def addFailure(self, test, err):
        super().addFailure(test, err)
        self._print(test, err)

    def _print(self, test, err):
        self.buffer = False
        self._pdbr.message(f"\n{test}")
        self._pdbr.error("%s: %s", err[0].__name__, err[1])
        post_mortem(err[2])


class PdbrDiscoverRunner(DiscoverRunner):
    def get_resultclass(self):
        if self.debug_sql:
            return DebugSQLTextTestResult
        return PDBRDebugResult


================================================
FILE: pdbr/utils.py
================================================
import atexit
import configparser
import os
from pathlib import Path

from pdbr._pdbr import rich_pdb_klass

try:
    import readline
except ImportError:
    try:
        from pyreadline3 import Readline

        readline = Readline()
    except ModuleNotFoundError:
        readline = None
except AttributeError:
    readline = None


def set_history_file(history_file):
    """
    This is just for Pdb,
    For Ipython, look at RichPdb.pt_init
    """
    if readline is None:
        return
    try:
        readline.read_history_file(history_file)
        readline.set_history_length(1000)
    except FileNotFoundError:
        pass
    except OSError:
        pass

    atexit.register(readline.write_history_file, history_file)


def set_traceback(theme):
    from rich.traceback import install

    install(theme=theme)


def read_config():
    style = None
    theme = None
    store_history = ".pdbr_history"
    context = None

    config = configparser.ConfigParser()
    config.sections()

    setup_filename = "setup.cfg"
    xdg_config_home = Path(os.getenv("XDG_CONFIG_HOME", Path.home() / ".config"))
    global_config_path = xdg_config_home / "pdbr" / setup_filename
    cwd_config_path = Path.cwd() / setup_filename
    config_path = cwd_config_path.exists() and cwd_config_path or global_config_path

    config.read(config_path)
    if "pdbr" in config:
        if "style" in config["pdbr"]:
            style = config["pdbr"]["style"]

        if "theme" in config["pdbr"]:
            theme = config["pdbr"]["theme"]

        if "use_traceback" in config["pdbr"]:
            if config["pdbr"]["use_traceback"].lower() == "true":
                set_traceback(theme)
        else:
            set_traceback(theme)

        if "store_history" in config["pdbr"]:
            store_history = config["pdbr"]["store_history"]

        if "context" in config["pdbr"]:
            context = config["pdbr"]["context"]

    history_file = str(Path.home() / store_history)
    set_history_file(history_file)
    ipython_history_file = f"{history_file}_ipython"

    return style, theme, history_file, ipython_history_file, context


def debugger_cls(
    klass=None, console=None, context=None, is_celery=False, show_layouts=True
):
    if klass is None:
        try:
            from IPython.terminal.debugger import TerminalPdb

            klass = TerminalPdb
        except ImportError:
            from pdb import Pdb

            klass = Pdb

    style, theme, history_file, ipython_history_file, config_context = read_config()
    RichPdb = rich_pdb_klass(
        klass,
        console=console,
        context=context if context is not None else config_context,
        is_celery=is_celery,
        show_layouts=show_layouts,
    )
    RichPdb._style = style
    RichPdb._theme = theme
    RichPdb._history_file = history_file
    RichPdb._ipython_history_file = ipython_history_file

    return RichPdb


def _pdbr_cls(console=None, context=None, return_instance=True, show_layouts=True):
    klass = debugger_cls(console=console, context=context, show_layouts=show_layouts)
    if return_instance:
        return klass()
    return klass


def _rdbr_cls(return_instance=True):
    try:
        from celery.contrib import rdb

        rdb.BANNER = """\
{self.ident}: Type `pdbr_telnet {self.host} {self.port}` to connect

{self.ident}: Waiting for client...
"""
    except ModuleNotFoundError as error:
        raise type(error)("In order to install celery, use pdbr[celery]") from error

    klass = debugger_cls(klass=rdb.Rdb, is_celery=True, show_layouts=False)
    if return_instance:
        return klass()
    return klass


================================================
FILE: pyproject.toml
================================================
[tool.poetry]
name = "pdbr"
version = "0.9.7"
description = "Pdb with Rich library."
authors = ["Can Sarigol <ertugrulsarigol@gmail.com>"]
packages = [
    { include = "pdbr" }
]
readme = "README.md"
homepage = "https://github.com/cansarigol/pdbr"
repository = "https://github.com/cansarigol/pdbr"
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "Operating System :: Microsoft :: Windows",
    "Operating System :: MacOS",
    "Operating System :: POSIX :: Linux",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Programming Language :: Python :: 3.14",
]

[tool.poetry.dependencies]
python = "^3.7.9"
rich = "*"
ipython = {version = "*", optional = true}
pyreadline3 = {version = "^3.4.1", markers = "sys_platform == 'win32'"}

[tool.poetry.extras]
ipython = ["ipython"]

[tool.poetry.scripts]
pdbr = 'pdbr.cli:shell'
pdbr_telnet = 'pdbr.cli:telnet'

[tool.poetry.group.dev.dependencies]
ruff = "^0.6.5"
nox = "^2024.4.15"

[build-system]
requires = ["poetry-core>=1.2.0"]
build-backend = "poetry.core.masonry.api"

[tool.vulture]
make_whitelist = true
min_confidence = 80
paths = ["pdbr", "tests"]
sort_by_size = true
verbose = false

[project]
name = "pdbr"
version = "0.9.7"

[tool.setuptools]
py-modules = []

[tool.ruff]
line-length = 88

[tool.ruff.lint]
select = [
    "E",  # pycodestyle errors
    "W",  # pycodestyle warnings
    "F",  # pyflakes
    "I",   # isort
    "B",   # flake8-bugbear
    "C4",  # flake8-comprehensions
    "PIE", # flake8-pie
    "ERA", # eradicate
]


================================================
FILE: runtests.py
================================================
import os
import sys

import django
from django.conf import settings
from django.test.utils import get_runner

if __name__ == "__main__":
    os.environ["DJANGO_SETTINGS_MODULE"] = "tests.tests_django.test_settings"
    django.setup()
    TestRunner = get_runner(settings)
    test_runner = TestRunner()
    failures = test_runner.run_tests(["tests"])
    sys.exit(bool(failures))


================================================
FILE: scripts/lint
================================================
#!/bin/sh -e

export SOURCE_FILES="pdbr tests noxfile.py"

ruff check $SOURCE_FILES --fix
black $SOURCE_FILES


================================================
FILE: scripts/test
================================================
#!/bin/sh -e
pre-commit run --all-files

poetry run nox --sessions test django_test


================================================
FILE: setup.cfg
================================================
[tool:pytest]
addopts = --capture=no --disable-warnings

[pdbr]
use_traceback= True
style=dim
store_history=.pdbr_history


================================================
FILE: tests/__init__.py
================================================


================================================
FILE: tests/conftest.py
================================================
"""
Add '--skip-slow' cmdline option to skip tests that are marked with @pytest.mark.slow.
"""

import pytest


def pytest_addoption(parser):
    parser.addoption(
        "--skip-slow", action="store_true", default=False, help="Skip slow tests"
    )


def pytest_collection_modifyitems(config, items):
    if not config.getoption("--skip-slow"):
        return
    skip_slow = pytest.mark.skip(reason="Specified --skip-slow")
    for item in items:
        if "slow" in item.keywords:
            item.add_marker(skip_slow)


================================================
FILE: tests/test_api.py
================================================
import pdbr


def test_api_attr():
    assert pdbr.__all__ == [
        "set_trace",
        "run",
        "pm",
        "post_mortem",
        "celery_set_trace",
        "RichPdb",
        "pdbr_context",
        "apdbr_context",
    ]


================================================
FILE: tests/test_config.py
================================================
import os
from pathlib import Path
from tempfile import TemporaryDirectory

import pytest

from pdbr.utils import read_config

root_dir = Path(__file__).parents[1]


@pytest.fixture
def dummy_global_config():
    XDG_CONFIG_HOME = Path.home() / ".config"
    pdbr_dir = XDG_CONFIG_HOME / "pdbr"
    pdbr_dir.mkdir(exist_ok=True, parents=True)
    setup_file = pdbr_dir / "setup.cfg"
    backup_file = pdbr_dir / (setup_file.stem + ".cfg.bak")

    if setup_file.exists():
        setup_file.rename(backup_file)

    with open(setup_file, "wt") as f:
        f.writelines(["[pdbr]\n", "theme = ansi_light"])

    yield setup_file

    setup_file.unlink()

    if backup_file.exists():
        backup_file.rename(setup_file)


def test_global_config(dummy_global_config):
    assert dummy_global_config.exists()

    tmpdir = TemporaryDirectory()
    os.chdir(tmpdir.name)

    # Second element of tuple is theme
    assert read_config()[1] == "ansi_light"
    os.chdir(root_dir)


def test_local_config():
    tmpdir = TemporaryDirectory()
    os.chdir(tmpdir.name)
    setup_file = Path(tmpdir.name) / "setup.cfg"

    with open(setup_file, "wt") as f:
        f.writelines(["[pdbr]\n", "theme = ansi_dark"])

    assert read_config()[1] == "ansi_dark"
    os.chdir(root_dir)


def test_read_config():
    pdbr_history = str(Path.home() / ".pdbr_history")
    pdbr_history_ipython = str(Path.home() / ".pdbr_history_ipython")

    assert read_config() == ("dim", None, pdbr_history, pdbr_history_ipython, None)


================================================
FILE: tests/test_magic.py
================================================
import inspect
import re
import sys
from pathlib import Path

import pytest
from rich.console import Console
from rich.theme import Theme

from pdbr._pdbr import rich_pdb_klass

NUMBER_RE = r"[\d.e+_,-]+"  # Matches 1e+03, 1.0e-03, 1_000, 1,000

TAG_RE = re.compile(r"\x1b[\[\]]+[\dDClhJt;?]+m?")


def untag(s):
    """Not perfect, but does the job.
    >>> untag('\x1b[0mfoo\x1b[0m\x1b[0;34m(\x1b[0m\x1b[0marg\x1b[0m\x1b[0;34m)\x1b[0m'
    >>>       '\x1b[0;34m\x1b[0m\x1b[0;34m\x1b[0m\x1b[0m')
    'foo(arg)'
    """
    s = s.replace("\x07", "")
    s = s.replace("\x1b[?2004l", "")
    return TAG_RE.sub("", s)


def unquote(s):
    """
    >>> unquote('"foo"')
    'foo'
    >>> unquote('"foo"bar')
    '"foo"bar'
    """
    for quote in ('"', "'"):
        if s.startswith(quote) and s.endswith(quote):
            return s[1:-1]
    return s


TMP_FILE_CONTENT = '''def foo(arg):
    """Foo docstring"""
    pass
    '''


def import_tmp_file(rpdb, tmp_path: Path, file_content=TMP_FILE_CONTENT) -> Path:
    """Creates a temporary file, writes `file_content` to it and makes pdbr import it"""
    tmp_file = tmp_path / "foo.py"
    tmp_file.write_text(file_content)

    rpdb.precmd(f'import sys; sys.path.append("{tmp_file.parent.absolute()}")')
    rpdb.precmd(f"from {tmp_file.stem} import foo")
    return tmp_file


@pytest.fixture
def pdbr_child_process(tmp_path):
    """
    Spawn a pdbr prompt in a child process.
    """
    from pexpect import spawn

    file = tmp_path / "foo.py"
    file.write_text("import pdbr;breakpoint()")

    child = spawn(
        str(Path(sys.executable)),
        [str(file)],
        encoding="utf-8",
    )
    child.expect("breakpoint")
    child.timeout = 10
    return child


@pytest.fixture
def RichIPdb():
    """
    In contrast to the normal RichPdb in test_pdbr.py which inherits from
    built-in pdb.Pdb, this one inherits from IPython's TerminalPdb, which holds
    a 'shell' attribute that is a IPython TerminalInteractiveShell.
    This is required for the magic commands to work (and happens automatically
    when the user runs pdbr when IPython is importable).
    """
    from IPython.terminal.debugger import TerminalPdb

    currentframe = inspect.currentframe()

    def rich_ipdb_klass(*args, **kwargs):
        ripdb = rich_pdb_klass(TerminalPdb, show_layouts=False)(*args, **kwargs)
        # Set frame and stack related self-attributes
        ripdb.botframe = currentframe.f_back
        ripdb.setup(currentframe.f_back, None)
        # Set the console's file to stdout so that we can capture the output
        _console = Console(
            file=kwargs.get("stdout", sys.stdout),
            theme=Theme(
                {"info": "dim cyan", "warning": "magenta", "danger": "bold red"}
            ),
        )
        ripdb._console = _console
        return ripdb

    return rich_ipdb_klass


@pytest.mark.skipif(sys.platform.startswith("win"), reason="pexpect")
@pytest.mark.slow
class TestPdbrChildProcess:
    def test_time(self, pdbr_child_process):
        pdbr_child_process.sendline("from time import sleep")
        pdbr_child_process.sendline("%time sleep(0.1)")
        pdbr_child_process.expect(re.compile("CPU times: .+"))
        pdbr_child_process.expect("Wall time: .+")

    def test_timeit(self, pdbr_child_process):
        pdbr_child_process.sendline("%timeit -n 1 -r 1 pass")
        pdbr_child_process.expect_exact("std. dev. of 1 run, 1 loop each)")


@pytest.mark.skipif(sys.platform.startswith("win"), reason="pexpect")
class TestPdbrMagic:
    def test_onecmd_time_line_magic(self, capsys, RichIPdb):
        RichIPdb().precmd("%time pass")
        captured = capsys.readouterr()
        output = captured.out
        assert re.search(
            f"CPU times: user {NUMBER_RE} [mµn]s, "
            f"sys: {NUMBER_RE} [mµn]s, "
            f"total: {NUMBER_RE} [mµn]s\n"
            f"Wall time: {NUMBER_RE} [mµn]s",
            output,
        )

    def test_onecmd_unsupported_cell_magic(self, capsys, RichIPdb):
        RichIPdb().precmd("%%time pass")
        captured = capsys.readouterr()
        output = captured.out
        error = (
            "Cell magics (multiline) are not yet supported. Use a single '%' instead."
        )
        assert output == "*** " + error + "\n"
        cmd = "%%time"
        stop = RichIPdb().precmd(cmd)
        captured_output = capsys.readouterr().out
        assert not stop
        RichIPdb().error(error)
        cell_magics_error = capsys.readouterr().out
        assert cell_magics_error == captured_output

    def test_onecmd_lsmagic_line_magic(self, capsys, RichIPdb):
        RichIPdb().precmd("%lsmagic")
        captured = capsys.readouterr()
        output = captured.out

        assert re.search(
            "Available line magics:\n%alias +%alias_magic +%autoawait.*%%writefile",
            output,
            re.DOTALL,
        )

    def test_no_zombie_lastcmd(self, capsys, RichIPdb):
        rpdb = RichIPdb(stdout=sys.stdout)
        rpdb.precmd("print('SHOULD_NOT_BE_IN_%pwd_OUTPUT')")
        captured = capsys.readouterr()
        assert captured.out.endswith(
            "SHOULD_NOT_BE_IN_%pwd_OUTPUT\n"
        )  # Starts with colors and prompt
        rpdb.precmd("%pwd")
        captured = capsys.readouterr()
        assert captured.out.endswith(Path.cwd().absolute().as_posix() + "\n")
        assert "SHOULD_NOT_BE_IN_%pwd_OUTPUT" not in captured.out

    def test_IPython_Pdb_magics_implementation(self, tmp_path, capsys, RichIPdb):
        """
        We test do_{magic} methods that are concretely implemented by
        IPython.core.debugger.Pdb, and don't default to IPython's
        'InteractiveShell.run_line_magic()' like the other magics.
        """
        from IPython.utils.text import dedent

        rpdb = RichIPdb(stdout=sys.stdout)
        tmp_file = import_tmp_file(rpdb, tmp_path)

        # pdef
        rpdb.do_pdef("foo")
        do_pdef_foo_output = capsys.readouterr().out
        untagged = untag(do_pdef_foo_output).strip()
        assert untagged.endswith("foo(arg)"), untagged
        rpdb.precmd("%pdef foo")
        magic_pdef_foo_output = capsys.readouterr().out
        untagged = untag(magic_pdef_foo_output).strip()
        assert untagged.endswith("foo(arg)"), untagged

        # pdoc
        rpdb.precmd("%pdoc foo")
        magic_pdef_foo_output = capsys.readouterr().out
        untagged = untag(magic_pdef_foo_output).strip()
        expected_docstring = dedent(
            """Class docstring:
            Foo docstring
        Call docstring:
            Call self as a function."""
        )
        assert untagged == expected_docstring, untagged

        # pfile
        rpdb.precmd("%pfile foo")
        magic_pfile_foo_output = capsys.readouterr().out
        untagged = untag(magic_pfile_foo_output).strip()
        tmp_file_content = Path(tmp_file).read_text().strip()
        assert untagged == tmp_file_content

        # pinfo
        rpdb.precmd("%pinfo foo")
        magic_pinfo_foo_output = capsys.readouterr().out
        untagged = untag(magic_pinfo_foo_output).strip()
        expected_pinfo = dedent(
            f"""Signature: foo(arg)
        Docstring: Foo docstring
        File:      {tmp_file.absolute()}
        Type:      function"""
        )
        assert untagged == expected_pinfo, untagged

        # pinfo2
        rpdb.precmd("%pinfo2 foo")
        magic_pinfo2_foo_output = capsys.readouterr().out
        untagged = untag(magic_pinfo2_foo_output).strip()
        expected_pinfo2 = re.compile(
            dedent(
                rf"""Signature: foo\(arg\)
        Source:\s*
        %s
        File:      {tmp_file.absolute()}
        Type:      function"""
            )
            % re.escape(tmp_file_content)
        )
        assert expected_pinfo2.fullmatch(untagged), untagged

        # psource
        rpdb.precmd("%psource foo")
        magic_psource_foo_output = capsys.readouterr().out
        untagged = untag(magic_psource_foo_output).strip()
        expected_psource = 'def foo(arg):\n    """Foo docstring"""\n    pass'
        assert untagged == expected_psource, untagged

    def test_expr_questionmark_pinfo(self, tmp_path, capsys, RichIPdb):
        from IPython.utils.text import dedent

        rpdb = RichIPdb(stdout=sys.stdout)
        tmp_file = import_tmp_file(rpdb, tmp_path)
        # pinfo
        rpdb.precmd(rpdb.precmd("foo?"))
        magic_foo_qmark_output = capsys.readouterr().out
        untagged = untag(magic_foo_qmark_output).strip()

        expected_pinfo_path = (
            f"/private/var/folders/.*/{tmp_file.name}"
            if sys.platform == "darwin"
            else f"/tmp/.*/{tmp_file.name}"
        )
        expected_pinfo = re.compile(
            dedent(
                rf""".*Signature: foo\(arg\)
        Docstring: Foo docstring
        File:      {expected_pinfo_path}
        Type:      function"""
            )
        )
        assert expected_pinfo.fullmatch(untagged), f"untagged = {untagged!r}"

        # pinfo2
        rpdb.precmd(rpdb.precmd("foo??"))
        magic_foo_qmark2_output = capsys.readouterr().out
        rpdb.precmd(rpdb.precmd("%pinfo2 foo"))
        magic_pinfo2_foo_output = capsys.readouterr().out
        assert magic_pinfo2_foo_output == magic_foo_qmark2_output

    def test_filesystem_magics(self, capsys, RichIPdb):
        cwd = Path.cwd().absolute().as_posix()
        rpdb = RichIPdb(stdout=sys.stdout)
        rpdb.precmd("%pwd")
        pwd_output = capsys.readouterr().out.strip()
        assert pwd_output == cwd
        rpdb.precmd("import os; os.getcwd()")
        pwd_output = unquote(capsys.readouterr().out.strip())
        assert pwd_output == cwd

        new_dir = str(Path.cwd().absolute().parent)
        rpdb.precmd(f"%cd {new_dir}")
        cd_output = untag(capsys.readouterr().out.strip())
        assert cd_output.endswith(new_dir)
        rpdb.precmd("%pwd")
        pwd_output = capsys.readouterr().out.strip()
        assert pwd_output == new_dir
        rpdb.precmd("import os; os.getcwd()")
        pwd_output = unquote(capsys.readouterr().out.strip())
        assert pwd_output == new_dir


================================================
FILE: tests/test_pdbr.py
================================================
import inspect
import pdb

import pytest

from pdbr._pdbr import rich_pdb_klass


@pytest.fixture
def RichPdb(*args, **kwargs):
    currentframe = inspect.currentframe()

    def wrapper():
        rpdb = rich_pdb_klass(pdb.Pdb, show_layouts=False)(*args, **kwargs)
        # Set frame and stack related self-attributes
        rpdb.botframe = currentframe.f_back
        rpdb.setup(currentframe.f_back, None)
        return rpdb

    return wrapper


def test_prompt(RichPdb):
    assert RichPdb().prompt == "(Pdbr) "


def test_print(capsys, RichPdb):
    RichPdb()._print("msg")
    captured = capsys.readouterr()
    assert captured.out == "msg\n"


def test_print_error(capsys, RichPdb):
    RichPdb().error("error")
    captured = capsys.readouterr()
    assert captured.out == "\x1b[1;31m*** error\x1b[0m\n"


def test_print_with_style(capsys, RichPdb):
    RichPdb()._print("msg", style="yellow")
    captured = capsys.readouterr()
    assert captured.out == "\x1b[33mmsg\x1b[0m\n"


def test_print_without_escape_tag(capsys, RichPdb):
    RichPdb()._print("[blue]msg[/]")
    captured = capsys.readouterr()
    assert captured.out == "\x1b[34mmsg\x1b[0m\n"


def test_print_array(capsys, RichPdb):
    RichPdb()._print("[[8]]")
    captured = capsys.readouterr()
    assert (
        captured.out == "\x1b[1m[\x1b[0m\x1b[1m[\x1b[0m\x1b[1;36m8"
        "\x1b[0m\x1b[1m]\x1b[0m\x1b[1m]\x1b[0m\n"
    )


def test_onecmd(capsys, RichPdb):
    rpdb = RichPdb()
    cmd = 'print("msg")'
    stop = rpdb.precmd(cmd)
    captured = capsys.readouterr()
    assert not stop
    assert captured.out == "msg\n"


================================================
FILE: tests/tests_django/__init__.py
================================================


================================================
FILE: tests/tests_django/test_settings.py
================================================
from pathlib import Path

BASE_DIR = Path(__file__).absolute().parents[1]

SECRET_KEY = "fake-key"
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": str(BASE_DIR / "db.sqlite3"),
    }
}

INSTALLED_APPS = ("tests.tests_django",)

TEST_RUNNER = "pdbr.runner.PdbrDiscoverRunner"

ROOT_URLCONF = "tests.tests_django.urls"

MIDDLEWARE = ["pdbr.middlewares.django.PdbrMiddleware"]


================================================
FILE: tests/tests_django/tests.py
================================================
from django.test import TestCase


class DjangoTest(TestCase):
    def test_runner(self):
        self.assertEqual("foo", "foo")

    def test_middleware(self):
        response = self.client.get("")
        self.assertEqual(response.status_code, 200)


================================================
FILE: tests/tests_django/urls.py
================================================
from django.http import HttpResponse
from django.urls import path

urlpatterns = [
    path("", lambda request: HttpResponse()),
]
Download .txt
gitextract_rmp4r7u5/

├── .github/
│   └── workflows/
│       ├── release.yml
│       └── tests.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .vscode/
│   └── settings.json
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── noxfile.py
├── pdbr/
│   ├── __init__.py
│   ├── __main__.py
│   ├── _cm.py
│   ├── _console_layout.py
│   ├── _pdbr.py
│   ├── cli.py
│   ├── helpers.py
│   ├── middlewares/
│   │   ├── __init__.py
│   │   ├── django.py
│   │   └── starlette.py
│   ├── runner.py
│   └── utils.py
├── pyproject.toml
├── runtests.py
├── scripts/
│   ├── lint
│   └── test
├── setup.cfg
└── tests/
    ├── __init__.py
    ├── conftest.py
    ├── test_api.py
    ├── test_config.py
    ├── test_magic.py
    ├── test_pdbr.py
    └── tests_django/
        ├── __init__.py
        ├── test_settings.py
        ├── tests.py
        └── urls.py
Download .txt
SYMBOL INDEX (81 symbols across 17 files)

FILE: noxfile.py
  function test (line 7) | def test(session, reuse_venv=True):
  function django_test (line 29) | def django_test(session, django, reuse_venv=True):

FILE: pdbr/__main__.py
  function set_trace (line 12) | def set_trace(*, console=None, header=None, context=None, show_layouts=F...
  function run (line 19) | def run(statement, globals=None, locals=None):
  function post_mortem (line 23) | def post_mortem(traceback=None, value=None):
  function pm (line 40) | def pm():
  function celery_set_trace (line 44) | def celery_set_trace(frame=None):
  function main (line 51) | def main():

FILE: pdbr/_cm.py
  class pdbr_context (line 7) | class pdbr_context(ContextDecorator):
    method __init__ (line 8) | def __init__(self, suppress_exc=True, debug=True):
    method __enter__ (line 12) | def __enter__(self):
    method __exit__ (line 15) | def __exit__(self, _, exc_value, exc_traceback):
  class AsyncContextDecorator (line 22) | class AsyncContextDecorator(ContextDecorator):
    method __call__ (line 23) | def __call__(self, func):
  class apdbr_context (line 32) | class apdbr_context(AsyncContextDecorator):
    method __init__ (line 33) | def __init__(self, suppress_exc=True, debug=True):
    method __aenter__ (line 37) | async def __aenter__(self):
    method __aexit__ (line 40) | async def __aexit__(self, _, exc_value, exc_traceback):

FILE: pdbr/_console_layout.py
  class ConsoleLayoutMeta (line 7) | class ConsoleLayoutMeta(type):
    method __call__ (line 10) | def __call__(cls, *args, **kwargs):
  class ConsoleLayout (line 17) | class ConsoleLayout(metaclass=ConsoleLayoutMeta):
    method __init__ (line 18) | def __init__(self, console):
    method _prep_layout (line 22) | def _prep_layout(self):
    method print (line 37) | def print(self, message, code, stack_trace, vars, **kwargs):

FILE: pdbr/_pdbr.py
  class AsciiStdout (line 34) | class AsciiStdout(io.TextIOWrapper):
  function rich_pdb_klass (line 38) | def rich_pdb_klass(

FILE: pdbr/cli.py
  function shell (line 9) | def shell():
  function telnet (line 22) | def telnet():

FILE: pdbr/helpers.py
  function run_ipython_shell (line 6) | def run_ipython_shell():

FILE: pdbr/middlewares/django.py
  class PdbrMiddleware (line 9) | class PdbrMiddleware:
    method __init__ (line 10) | def __init__(self, get_response):
    method __call__ (line 15) | def __call__(self, request):
    method process_exception (line 18) | def process_exception(self, request, exception):  # noqa: F841

FILE: pdbr/middlewares/starlette.py
  class PdbrMiddleware (line 6) | class PdbrMiddleware(ServerErrorMiddleware):
    method __call__ (line 7) | async def __call__(self, scope, receive, send) -> None:

FILE: pdbr/runner.py
  class PDBRDebugResult (line 8) | class PDBRDebugResult(unittest.TextTestResult):
    method addError (line 11) | def addError(self, test, err):
    method addFailure (line 15) | def addFailure(self, test, err):
    method _print (line 19) | def _print(self, test, err):
  class PdbrDiscoverRunner (line 26) | class PdbrDiscoverRunner(DiscoverRunner):
    method get_resultclass (line 27) | def get_resultclass(self):

FILE: pdbr/utils.py
  function set_history_file (line 21) | def set_history_file(history_file):
  function set_traceback (line 39) | def set_traceback(theme):
  function read_config (line 45) | def read_config():
  function debugger_cls (line 87) | def debugger_cls(
  function _pdbr_cls (line 116) | def _pdbr_cls(console=None, context=None, return_instance=True, show_lay...
  function _rdbr_cls (line 123) | def _rdbr_cls(return_instance=True):

FILE: tests/conftest.py
  function pytest_addoption (line 8) | def pytest_addoption(parser):
  function pytest_collection_modifyitems (line 14) | def pytest_collection_modifyitems(config, items):

FILE: tests/test_api.py
  function test_api_attr (line 4) | def test_api_attr():

FILE: tests/test_config.py
  function dummy_global_config (line 13) | def dummy_global_config():
  function test_global_config (line 34) | def test_global_config(dummy_global_config):
  function test_local_config (line 45) | def test_local_config():
  function test_read_config (line 57) | def test_read_config():

FILE: tests/test_magic.py
  function untag (line 17) | def untag(s):
  function unquote (line 28) | def unquote(s):
  function import_tmp_file (line 47) | def import_tmp_file(rpdb, tmp_path: Path, file_content=TMP_FILE_CONTENT)...
  function pdbr_child_process (line 58) | def pdbr_child_process(tmp_path):
  function RichIPdb (line 78) | def RichIPdb():
  class TestPdbrChildProcess (line 110) | class TestPdbrChildProcess:
    method test_time (line 111) | def test_time(self, pdbr_child_process):
    method test_timeit (line 117) | def test_timeit(self, pdbr_child_process):
  class TestPdbrMagic (line 123) | class TestPdbrMagic:
    method test_onecmd_time_line_magic (line 124) | def test_onecmd_time_line_magic(self, capsys, RichIPdb):
    method test_onecmd_unsupported_cell_magic (line 136) | def test_onecmd_unsupported_cell_magic(self, capsys, RichIPdb):
    method test_onecmd_lsmagic_line_magic (line 152) | def test_onecmd_lsmagic_line_magic(self, capsys, RichIPdb):
    method test_no_zombie_lastcmd (line 163) | def test_no_zombie_lastcmd(self, capsys, RichIPdb):
    method test_IPython_Pdb_magics_implementation (line 175) | def test_IPython_Pdb_magics_implementation(self, tmp_path, capsys, Ric...
    method test_expr_questionmark_pinfo (line 250) | def test_expr_questionmark_pinfo(self, tmp_path, capsys, RichIPdb):
    method test_filesystem_magics (line 282) | def test_filesystem_magics(self, capsys, RichIPdb):

FILE: tests/test_pdbr.py
  function RichPdb (line 10) | def RichPdb(*args, **kwargs):
  function test_prompt (line 23) | def test_prompt(RichPdb):
  function test_print (line 27) | def test_print(capsys, RichPdb):
  function test_print_error (line 33) | def test_print_error(capsys, RichPdb):
  function test_print_with_style (line 39) | def test_print_with_style(capsys, RichPdb):
  function test_print_without_escape_tag (line 45) | def test_print_without_escape_tag(capsys, RichPdb):
  function test_print_array (line 51) | def test_print_array(capsys, RichPdb):
  function test_onecmd (line 60) | def test_onecmd(capsys, RichPdb):

FILE: tests/tests_django/tests.py
  class DjangoTest (line 4) | class DjangoTest(TestCase):
    method test_runner (line 5) | def test_runner(self):
    method test_middleware (line 8) | def test_middleware(self):
Condensed preview — 37 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (65K chars).
[
  {
    "path": ".github/workflows/release.yml",
    "chars": 560,
    "preview": "name: Release\n\non:\n  push:\n    tags:\n      - '*'\n  workflow_dispatch:\n\njobs:\n  build-n-publish:\n    name: Build and publ"
  },
  {
    "path": ".github/workflows/tests.yml",
    "chars": 1047,
    "preview": "name: Test\n\non:\n  push:\n    branches: [\"master\"]\n  pull_request:\n    branches: [\"master\"]\n\njobs:\n  check:\n    name: \"Che"
  },
  {
    "path": ".gitignore",
    "chars": 2055,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 779,
    "preview": "repos:\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: v5.0.0\n    hooks:\n      - id: check-added-large"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 54,
    "preview": "{\n    \"makefile.extensionOutputFolder\": \"./.vscode\"\n}\n"
  },
  {
    "path": "Dockerfile",
    "chars": 206,
    "preview": "FROM python:3.7.9\n\nENV PYTHONUNBUFFERED=0\n\nRUN pip install pip \\\n && pip install nox \\\n && pip install pre-commit\n\nWORKD"
  },
  {
    "path": "LICENSE",
    "chars": 1068,
    "preview": "MIT License\n\nCopyright (c) 2020 Can Sarıgöl\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "Makefile",
    "chars": 187,
    "preview": "lint:\n\tsh scripts/lint\n\ntest:\n\tsh scripts/test\n\ncelery:\n\tcelery -A tasks worker --loglevel=info\n\nbuild:\n\tdocker build -t"
  },
  {
    "path": "README.md",
    "chars": 7916,
    "preview": "# pdbr\n\n[![PyPI version](https://badge.fury.io/py/pdbr.svg)](https://pypi.org/project/pdbr/) [![Python Version](https://"
  },
  {
    "path": "noxfile.py",
    "chars": 634,
    "preview": "import nox\n\nnox.options.stop_on_first_error = True\n\n\n@nox.session\ndef test(session, reuse_venv=True):\n    session.instal"
  },
  {
    "path": "pdbr/__init__.py",
    "chars": 286,
    "preview": "from pdbr.__main__ import RichPdb, celery_set_trace, pm, post_mortem, run, set_trace\nfrom pdbr._cm import apdbr_context,"
  },
  {
    "path": "pdbr/__main__.py",
    "chars": 1270,
    "preview": "import os\nimport pdb\nimport sys\n\nfrom .utils import _pdbr_cls, _rdbr_cls\n\nos.environ[\"PYTHONBREAKPOINT\"] = \"pdbr.set_tra"
  },
  {
    "path": "pdbr/_cm.py",
    "chars": 1206,
    "preview": "from contextlib import ContextDecorator\nfrom functools import wraps\n\nfrom pdbr.__main__ import post_mortem\n\n\nclass pdbr_"
  },
  {
    "path": "pdbr/_console_layout.py",
    "chars": 1485,
    "preview": "from rich.containers import Lines\nfrom rich.errors import NotRenderableError\nfrom rich.layout import Layout\nfrom rich.pa"
  },
  {
    "path": "pdbr/_pdbr.py",
    "chars": 16375,
    "preview": "import inspect\nimport io\nimport re\nfrom pathlib import Path\nfrom pdb import Pdb\n\nfrom rich import box, markup\nfrom rich."
  },
  {
    "path": "pdbr/cli.py",
    "chars": 1306,
    "preview": "import sys\nfrom telnetlib import Telnet\n\nfrom rich.file_proxy import FileProxy\n\nfrom pdbr.helpers import run_ipython_she"
  },
  {
    "path": "pdbr/helpers.py",
    "chars": 1421,
    "preview": "import sys\n\nfrom pdbr.__main__ import RichPdb\n\n\ndef run_ipython_shell():\n    try:\n        from IPython.terminal.interact"
  },
  {
    "path": "pdbr/middlewares/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "pdbr/middlewares/django.py",
    "chars": 492,
    "preview": "import sys\n\nfrom django.conf import settings\nfrom django.core.exceptions import MiddlewareNotUsed\n\nfrom pdbr.__main__ im"
  },
  {
    "path": "pdbr/middlewares/starlette.py",
    "chars": 334,
    "preview": "from starlette.middleware.errors import ServerErrorMiddleware\n\nfrom pdbr._cm import apdbr_context\n\n\nclass PdbrMiddleware"
  },
  {
    "path": "pdbr/runner.py",
    "chars": 782,
    "preview": "import unittest\n\nfrom django.test.runner import DebugSQLTextTestResult, DiscoverRunner\n\nfrom pdbr.__main__ import RichPd"
  },
  {
    "path": "pdbr/utils.py",
    "chars": 3653,
    "preview": "import atexit\nimport configparser\nimport os\nfrom pathlib import Path\n\nfrom pdbr._pdbr import rich_pdb_klass\n\ntry:\n    im"
  },
  {
    "path": "pyproject.toml",
    "chars": 1769,
    "preview": "[tool.poetry]\nname = \"pdbr\"\nversion = \"0.9.7\"\ndescription = \"Pdb with Rich library.\"\nauthors = [\"Can Sarigol <ertugrulsa"
  },
  {
    "path": "runtests.py",
    "chars": 381,
    "preview": "import os\nimport sys\n\nimport django\nfrom django.conf import settings\nfrom django.test.utils import get_runner\n\nif __name"
  },
  {
    "path": "scripts/lint",
    "chars": 110,
    "preview": "#!/bin/sh -e\n\nexport SOURCE_FILES=\"pdbr tests noxfile.py\"\n\nruff check $SOURCE_FILES --fix\nblack $SOURCE_FILES\n"
  },
  {
    "path": "scripts/test",
    "chars": 84,
    "preview": "#!/bin/sh -e\npre-commit run --all-files\n\npoetry run nox --sessions test django_test\n"
  },
  {
    "path": "setup.cfg",
    "chars": 122,
    "preview": "[tool:pytest]\naddopts = --capture=no --disable-warnings\n\n[pdbr]\nuse_traceback= True\nstyle=dim\nstore_history=.pdbr_histor"
  },
  {
    "path": "tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/conftest.py",
    "chars": 526,
    "preview": "\"\"\"\nAdd '--skip-slow' cmdline option to skip tests that are marked with @pytest.mark.slow.\n\"\"\"\n\nimport pytest\n\n\ndef pyte"
  },
  {
    "path": "tests/test_api.py",
    "chars": 239,
    "preview": "import pdbr\n\n\ndef test_api_attr():\n    assert pdbr.__all__ == [\n        \"set_trace\",\n        \"run\",\n        \"pm\",\n      "
  },
  {
    "path": "tests/test_config.py",
    "chars": 1511,
    "preview": "import os\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\n\nimport pytest\n\nfrom pdbr.utils import read_c"
  },
  {
    "path": "tests/test_magic.py",
    "chars": 10185,
    "preview": "import inspect\nimport re\nimport sys\nfrom pathlib import Path\n\nimport pytest\nfrom rich.console import Console\nfrom rich.t"
  },
  {
    "path": "tests/test_pdbr.py",
    "chars": 1609,
    "preview": "import inspect\nimport pdb\n\nimport pytest\n\nfrom pdbr._pdbr import rich_pdb_klass\n\n\n@pytest.fixture\ndef RichPdb(*args, **k"
  },
  {
    "path": "tests/tests_django/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/tests_django/test_settings.py",
    "chars": 421,
    "preview": "from pathlib import Path\n\nBASE_DIR = Path(__file__).absolute().parents[1]\n\nSECRET_KEY = \"fake-key\"\nDATABASES = {\n    \"de"
  },
  {
    "path": "tests/tests_django/tests.py",
    "chars": 252,
    "preview": "from django.test import TestCase\n\n\nclass DjangoTest(TestCase):\n    def test_runner(self):\n        self.assertEqual(\"foo\""
  },
  {
    "path": "tests/tests_django/urls.py",
    "chars": 131,
    "preview": "from django.http import HttpResponse\nfrom django.urls import path\n\nurlpatterns = [\n    path(\"\", lambda request: HttpResp"
  }
]

About this extraction

This page contains the full source code of the cansarigol/pdbr GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 37 files (59.0 KB), approximately 15.8k tokens, and a symbol index with 81 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!