Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
krassowski committed Feb 19, 2024
0 parents commit c7a63df
Show file tree
Hide file tree
Showing 13 changed files with 616 additions and 0 deletions.
44 changes: 44 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: tests

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:
strategy:
matrix:
os: [ubuntu-latest]
python-version: ['3.10', '3.11', '3.12']
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install test dependencies
run: |
python -m pip install --upgrade pip wheel
- name: Temporary installation
run: python -m pip install -e .[dev,test]
- name: Test with pytest
run: |
ipython -m pytest
- name: Check types with mypy
run: |
mypy ipython_markdown_inspector
- name: Build package
run: |
python -m build
- name: Install package
run: python -m pip install --find-links=dist --ignore-installed ipython_markdown_inspector
- name: Pip check
run: python -m pip check
- name: Publish builds
uses: actions/upload-artifact@v4
with:
name: ipython_markdown_inspector dist Python${{ matrix.python-version }} run ${{ github.run_number }}
path: ./dist
160 changes: 160 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# 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

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__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/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
21 changes: 21 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: end-of-file-fixer
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: check-added-large-files
- id: check-case-conflict
- id: check-toml
- id: check-yaml
- id: debug-statements
- id: check-builtin-literals
- id: trailing-whitespace
- id: check-merge-conflict
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.0
hooks:
- id: ruff
args: ["--fix"]
- id: ruff-format
28 changes: 28 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
BSD 3-Clause License

Copyright (c) 2024, Michał Krassowski

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# ipython-markdown-inspector

[![tests](https://github.com/krassowski/ipython-markdown-inspector/workflows/tests/badge.svg)](https://github.com/krassowski/ipython-markdown-inspector/actions?query=workflow%3A%22tests%22)
![CodeQL](https://github.com/krassowski/ipython-markdown-inspector/workflows/CodeQL/badge.svg)
[![pypi-version](https://img.shields.io/pypi/v/ipython-markdown-inspector.svg)](https://python.org/pypi/ipython-markdown-inspector)

IPython extension providing Inspection outputs as Markdown, enabling better integration with Jupyter Notebook and JupyterLab.
Depends on [`docstring-to-markdown`](https://github.com/python-lsp/docstring-to-markdown).

![](https://raw.githubusercontent.com/krassowski/ipython-markdown-inspector/main/docs/demo.gif)

## Installation

Requires `IPython` 8.21 or newer (which requires Python 3.10 or newer).

```bash
pip install ipython-markdown-inspector
```

## Usage

To load an extension while IPython is running, use the `%load_ext` magic:

```ipython
%load_ext ipython_markdown_inspector
```

To load it each time IPython starts, list it in your [configuration file](https://ipython.readthedocs.io/en/stable/config/intro.html):

```python
c.InteractiveShellApp.extensions = [
'ipython_markdown_inspector'
]
```

After enabling the extension, both the contents of "Contextual Help" panel,
and results of info requests such as `%run?` or `df?` will provide the output in Markdown format.
Binary file added docs/demo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions ipython_markdown_inspector/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from functools import partial
from typing import Any, List, Optional, Union

from IPython.core.interactiveshell import InteractiveShell
from IPython.core.oinspect import OInfo

from ._hook_data import InspectorHookData
from .formatter import as_markdown


def hook(
obj_or_data: Union[InspectorHookData, Any],
info: Optional[OInfo] = None,
*_,
ipython: InteractiveShell,
) -> str:
if isinstance(obj_or_data, InspectorHookData):
data = obj_or_data
else:
# fallback for IPython 8.21
obj = obj_or_data
detail_level = 0
omit_sections: List[str] = []
info_dict = ipython.inspector.info(
obj, "", info=info, detail_level=detail_level
)
data = InspectorHookData(
obj=obj,
info=info,
info_dict=info_dict,
detail_level=detail_level,
omit_sections=omit_sections,
)
return as_markdown(data)


ORIGINAL_HOOK = None


def load_ipython_extension(ipython: InteractiveShell):
global ORIGINAL_HOOK
ORIGINAL_HOOK = ipython.inspector.mime_hooks.get("text/markdown", None)
ipython.inspector.mime_hooks["text/markdown"] = partial(hook, ipython=ipython)


def unload_ipython_extension(ipython: InteractiveShell):
if ORIGINAL_HOOK is None:
del ipython.inspector.mime_hooks["text/markdown"]
else:
ipython.inspector.mime_hooks["text/markdown"] = ORIGINAL_HOOK


__all__: List[str] = []
9 changes: 9 additions & 0 deletions ipython_markdown_inspector/_hook_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
try:
from IPython.core.oinspect import InspectorHookData # type: ignore
except ImportError:
# TODO: remove once we require a version which includes
# https://github.com/ipython/ipython/pull/14342
from ._ipython_patch import InspectorHookData


__all__ = ["InspectorHookData"]
40 changes: 40 additions & 0 deletions ipython_markdown_inspector/_ipython_patch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from typing import Any, TypedDict, Optional
from dataclasses import dataclass

from IPython.core.oinspect import OInfo


class InfoDict(TypedDict):
type_name: Optional[str]
base_class: Optional[str]
string_form: Optional[str]
namespace: Optional[str]
length: Optional[str]
file: Optional[str]
definition: Optional[str]
docstring: Optional[str]
source: Optional[str]
init_definition: Optional[str]
class_docstring: Optional[str]
init_docstring: Optional[str]
call_def: Optional[str]
call_docstring: Optional[str]
subclasses: Optional[str]
# These won't be printed but will be used to determine how to
# format the object
ismagic: bool
isalias: bool
isclass: bool
found: bool
name: str


@dataclass
class InspectorHookData:
"""Data passed to the mime hook"""

obj: Any
info: Optional[OInfo]
info_dict: InfoDict
detail_level: int
omit_sections: list[str]
Loading

0 comments on commit c7a63df

Please sign in to comment.