]>
git.madduck.net Git - etc/vim.git/blobdiff - src/black/handle_ipynb_magics.py
madduck's git repository
Every one of the projects in this repository is available at the canonical
URL git://git.madduck.net/madduck/pub/<projectpath> — see
each project's metadata for the exact URL.
All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@ git. madduck. net .
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
SSH access, as well as push access can be individually
arranged .
If you use my repositories frequently, consider adding the following
snippet to ~/.gitconfig and using the third clone URL listed for each
project:
[url "git://git.madduck.net/madduck/"]
insteadOf = madduck:
)
NON_PYTHON_CELL_MAGICS = frozenset(
(
)
NON_PYTHON_CELL_MAGICS = frozenset(
(
- "%% bash",
- "%% html",
- "%% javascript",
- "%% js",
- "%% latex",
- "%% markdown",
- "%% perl",
- "%% ruby",
- "%% script",
- "%% sh",
- "%% svg",
- "%% writefile",
+ "bash",
+ "html",
+ "javascript",
+ "js",
+ "latex",
+ "markdown",
+ "perl",
+ "ruby",
+ "script",
+ "sh",
+ "svg",
+ "writefile",
+TOKEN_HEX = secrets.token_hex
@dataclasses.dataclass(frozen=True)
@dataclasses.dataclass(frozen=True)
"""
assert magic
nbytes = max(len(magic) // 2 - 1, 1)
"""
assert magic
nbytes = max(len(magic) // 2 - 1, 1)
- token = secrets.token_hex (nbytes)
+ token = TOKEN_HEX (nbytes)
- while token in src: # pragma: nocover
- token = secrets.token_hex (nbytes)
+ while token in src:
+ token = TOKEN_HEX (nbytes)
counter += 1
if counter > 100:
raise AssertionError(
counter += 1
if counter > 100:
raise AssertionError(
cell_magic_finder.visit(tree)
if cell_magic_finder.cell_magic is None:
return src, replacements
cell_magic_finder.visit(tree)
if cell_magic_finder.cell_magic is None:
return src, replacements
- if cell_magic_finder.cell_magic.header.split()[0] in NON_PYTHON_CELL_MAGICS:
+ if cell_magic_finder.cell_magic.name in NON_PYTHON_CELL_MAGICS:
- mask = get_token(src, cell_magic_finder.cell_magic.header)
- replacements.append(Replacement(mask=mask, src=cell_magic_finder.cell_magic.header))
+ header = cell_magic_finder.cell_magic.header
+ mask = get_token(src, header)
+ replacements.append(Replacement(mask=mask, src=header))
return f"{mask}\n{cell_magic_finder.cell_magic.body}", replacements
return f"{mask}\n{cell_magic_finder.cell_magic.body}", replacements
+def _get_str_args(args: List[ast.expr]) -> List[str]:
+ str_args = []
+ for arg in args:
+ assert isinstance(arg, ast.Str)
+ str_args.append(arg.s)
+ return str_args
+
+
@dataclasses.dataclass(frozen=True)
class CellMagic:
@dataclasses.dataclass(frozen=True)
class CellMagic:
+ name: str
+ params: Optional[str]
+ @property
+ def header(self) -> str:
+ if self.params:
+ return f"%%{self.name} {self.params}"
+ return f"%%{self.name}"
+
+# ast.NodeVisitor + dataclass = breakage under mypyc.
class CellMagicFinder(ast.NodeVisitor):
"""Find cell magics.
class CellMagicFinder(ast.NodeVisitor):
"""Find cell magics.
and we look for instances of the latter.
"""
and we look for instances of the latter.
"""
- cell_magic: Optional[CellMagic] = None
+ def __init__(self, cell_magic: Optional[CellMagic] = None) -> None:
+ self.cell_magic = cell_magic
def visit_Expr(self, node: ast.Expr) -> None:
"""Find cell magic, extract header and body."""
def visit_Expr(self, node: ast.Expr) -> None:
"""Find cell magic, extract header and body."""
and _is_ipython_magic(node.value.func)
and node.value.func.attr == "run_cell_magic"
):
and _is_ipython_magic(node.value.func)
and node.value.func.attr == "run_cell_magic"
):
- args = []
- for arg in node.value.args:
- assert isinstance(arg, ast.Str)
- args.append(arg.s)
- header = f"%%{args[0]}"
- if args[1]:
- header += f" {args[1]}"
- self.cell_magic = CellMagic(header=header, body=args[2])
+ args = _get_str_args(node.value.args)
+ self.cell_magic = CellMagic(name=args[0], params=args[1], body=args[2])
+# Unsurprisingly, subclassing ast.NodeVisitor means we can't use dataclasses here
+# as mypyc will generate broken code.
class MagicFinder(ast.NodeVisitor):
"""Visit cell to look for get_ipython calls.
class MagicFinder(ast.NodeVisitor):
"""Visit cell to look for get_ipython calls.
- magics: Dict[int, List[OffsetAndMagic]] = dataclasses.field(
- default_factory=lambda: collections.defaultdict(list)
- )
+ def __init__(self) -> None:
+ self.magics: Dict[int, List[OffsetAndMagic]] = collections.defaultdict(list)
def visit_Assign(self, node: ast.Assign) -> None:
"""Look for system assign magics.
def visit_Assign(self, node: ast.Assign) -> None:
"""Look for system assign magics.
and _is_ipython_magic(node.value.func)
and node.value.func.attr == "getoutput"
):
and _is_ipython_magic(node.value.func)
and node.value.func.attr == "getoutput"
):
- args = []
- for arg in node.value.args:
- assert isinstance(arg, ast.Str)
- args.append(arg.s)
- assert args
- src = f"!{args[0]}"
+ (arg,) = _get_str_args(node.value.args)
+ src = f"!{arg}"
self.magics[node.value.lineno].append(
OffsetAndMagic(node.value.col_offset, src)
)
self.magics[node.value.lineno].append(
OffsetAndMagic(node.value.col_offset, src)
)
and we look for instances of any of the latter.
"""
if isinstance(node.value, ast.Call) and _is_ipython_magic(node.value.func):
and we look for instances of any of the latter.
"""
if isinstance(node.value, ast.Call) and _is_ipython_magic(node.value.func):
- args = []
- for arg in node.value.args:
- assert isinstance(arg, ast.Str)
- args.append(arg.s)
- assert args
+ args = _get_str_args(node.value.args)
if node.value.func.attr == "run_line_magic":
if args[0] == "pinfo":
src = f"?{args[1]}"
if node.value.func.attr == "run_line_magic":
if args[0] == "pinfo":
src = f"?{args[1]}"