Skip to content

Commit 1f948ef

Browse files
committed
Added a CLI flag for __init__.py generation and improved package imports
1 parent a4d63c9 commit 1f948ef

File tree

8 files changed

+56
-9
lines changed

8 files changed

+56
-9
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Changelog
22

3+
## 0.1.4 (2024-02-22)
4+
5+
[Compare the full difference.](https://github.com/ThunderStruct/nbrefactor/compare/0.1.3...0.1.4)
6+
7+
### Added
8+
9+
- Added new CLI flag `-i/--init-files` to optionally generate `__init__.py` files in package directories
10+
- Improved package imports by properly exposing modules in `__init__.py` files
11+
12+
### Fixed
13+
14+
- Fixed relative import issues by properly handling package hierarchy with `__init__.py` files
15+
316
## 0.1.3 (2025-02-18)
417

518
[Compare the full difference.](https://github.com/ThunderStruct/nbrefactor/compare/0.1.2...0.1.3)

TODO.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# Todo
32

43
- 🔴 High priority _(i.e. critical and urgent features / fixes)_
@@ -21,7 +20,7 @@
2120

2221
## Minor
2322

24-
- [ ] 🔴 Add a CLI flag to instantiate modules (add `__init__.py` to sub-directories in the writer phase).
23+
- [x] 🔴 Add a CLI flag to instantiate modules (add `__init__.py` to sub-directories in the writer phase).
2524
- [ ] 🟠 Add unit testing for the [CDA](src/nbrefactor/processor/cda.py), [Parser](src/nbrefactor/processor/parser.py), and [CLI](src/nbrefactor/cli.py). Integrate it into the CI workflow.
2625

2726

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name='nbrefactor',
8-
version='0.1.3',
8+
version='0.1.4',
99
author='Mohamed Shahawy',
1010
author_email='[email protected]',
1111
description='An automation tool to refactor Jupyter Notebooks to Python modules, with code dependency analysis.',

src/nbrefactor/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Current
2-
__version__ = '0.1.3'
2+
__version__ = '0.1.4'
33

44
# CLI
55
from .cli import main

src/nbrefactor/cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ def main():
1717
# refactoring
1818
root_node = process_notebook(notebook_path=args.notebook_path,
1919
output_path=args.output_path,
20-
root_package=args.root_package)
20+
root_package=args.root_package,
21+
generate_init=args.generate_init)
2122

2223
# plotting (if applicable)
2324
if args.generate_plot:

src/nbrefactor/fileops/writer.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from ..datastructs import ParsedCodeCell
77

88

9-
def write_modules(node, output_path, pre_write_hook=None):
9+
def write_modules(node, output_path, pre_write_hook=None, generate_init=False):
1010
"""
1111
Recursively writes the modules and their contents given a \
1212
:class:`~nbrefactor.datastructs.ModuleNode` tree hierarchy.
@@ -16,6 +16,8 @@ def write_modules(node, output_path, pre_write_hook=None):
1616
output_path (str): the path where the Python files should be written.
1717
write_hook (callable, optional): a hook function that takes \
1818
(content, node) and returns the modified content.
19+
generate_init (bool, optional): whether to generate __init__.py files \
20+
in package directories. Defaults to False.
1921
"""
2022

2123
if (not node.children and node.has_code_cells()) \
@@ -35,6 +37,26 @@ def write_modules(node, output_path, pre_write_hook=None):
3537
module_path = os.path.join(output_path, node.name)
3638
ensure_dir(module_path)
3739

40+
# create `__init__.py` file for package if requested
41+
if generate_init and node.name != '.': # skip root directory
42+
init_path = os.path.join(module_path, '__init__.py')
43+
with open(init_path, 'w') as f:
44+
# write package docstring
45+
f.write('"""Package initialization."""\n\n')
46+
47+
# if this node has code cells, expose them at package level
48+
if node.has_code_cells():
49+
module_name = os.path.splitext(node.name)[0]
50+
# noqa to supress import warnings (refer to PEP 8)
51+
f.write(f'from .{module_name} import * # noqa\n')
52+
53+
# expose all child modules
54+
for child in node.children.values():
55+
if not child.ignore_package and not child.ignore_module:
56+
child_name = os.path.splitext(child.name)[0]
57+
# noqa to supress import warnings
58+
f.write(f'from .{child_name} import * # noqa\n')
59+
3860
# node could potentially have code at package-level, so...
3961
if node.has_code_cells():
4062
__write_module_node(node, module_path,
@@ -43,7 +65,9 @@ def write_modules(node, output_path, pre_write_hook=None):
4365

4466
# recursively write child nodes
4567
for child in node.children.values():
46-
write_modules(child, module_path, pre_write_hook=pre_write_hook)
68+
write_modules(child, module_path,
69+
pre_write_hook=pre_write_hook,
70+
generate_init=generate_init)
4771

4872

4973
def __write_module_node(node, output_path,

src/nbrefactor/processor/processor.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414

1515
def process_notebook(notebook_path, output_path,
16-
root_package='.', pre_write_hook=None):
16+
root_package='.', pre_write_hook=None, generate_init=False):
1717
"""
1818
The Notebook-refactoring entry point. This function:
1919
@@ -37,6 +37,8 @@ def process_notebook(notebook_path, output_path,
3737
`output_path`).
3838
write_hook (callable, optional): a hook function that takes (content, \
3939
node) and returns the modified content.
40+
generate_init (bool, optional): whether to generate __init__.py files \
41+
in package directories. Defaults to False.
4042
4143
Returns:
4244
:class:`~nbrefactor.datastructs.ModuleNode`: the root node of the \
@@ -165,7 +167,8 @@ def write_hook_wrapper(content, node):
165167
return content
166168

167169
write_modules(root, output_path,
168-
pre_write_hook=write_hook_wrapper)
170+
pre_write_hook=write_hook_wrapper,
171+
generate_init=generate_init)
169172

170173
Logger.log((
171174
f'Successfully wrote ({file_counter}) files to "{output_path}"!\n'

src/nbrefactor/utils/argument_parsing.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ def parse_args():
2121
Defaults to `False`.
2222
-pf, --plot-format (str): format of the plot (e.g., "pdf", "png"). \
2323
Defaults to "pdf".
24+
-i, --init-files: generate __init__.py files in package directories. \
25+
Defaults to `False`.
2426
2527
Returns:
2628
argparse.Namespace: parsed arguments from the command line.
@@ -65,4 +67,9 @@ def parse_args():
6567
help=('Format of the plot (e.g., "pdf", "png"). '
6668
'Defaults to "pdf".'))
6769

70+
parser.add_argument('-i', '--init-files',
71+
action='store_true',
72+
dest='generate_init',
73+
help='Generate __init__.py files in package directories.')
74+
6875
return parser.parse_args()

0 commit comments

Comments
 (0)