libjam 0.1.8__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. libjam-0.2.0/.gitignore +3 -0
  2. libjam-0.2.0/.readthedocs.yaml +17 -0
  3. libjam-0.2.0/PKG-INFO +40 -0
  4. libjam-0.2.0/README.md +20 -0
  5. libjam-0.2.0/docs/captain.rst +96 -0
  6. libjam-0.2.0/docs/conf.py +64 -0
  7. libjam-0.2.0/docs/drawer.rst +36 -0
  8. libjam-0.2.0/docs/flashcard.rst +47 -0
  9. libjam-0.2.0/docs/index.rst +43 -0
  10. libjam-0.2.0/docs/multicommand-example.py +44 -0
  11. libjam-0.2.0/docs/path.rst +35 -0
  12. libjam-0.2.0/docs/secretary.rst +75 -0
  13. libjam-0.2.0/docs/singlecommand-example.py +23 -0
  14. libjam-0.2.0/docs/static/style.css +26 -0
  15. libjam-0.2.0/docs/writer.rst +7 -0
  16. libjam-0.2.0/hooks/pre-commit +27 -0
  17. libjam-0.2.0/libjam/__init__.py +13 -0
  18. libjam-0.2.0/libjam/captain.py +463 -0
  19. libjam-0.2.0/libjam/drawer.py +372 -0
  20. libjam-0.2.0/libjam/flashcard.py +56 -0
  21. libjam-0.2.0/libjam/path.py +56 -0
  22. libjam-0.2.0/libjam/secretary.py +119 -0
  23. libjam-0.2.0/libjam/writer.py +495 -0
  24. libjam-0.2.0/pyproject.toml +48 -0
  25. {libjam-0.1.8 → libjam-0.2.0}/ruff.toml +2 -3
  26. libjam-0.1.8/.gitignore +0 -2
  27. libjam-0.1.8/PKG-INFO +0 -229
  28. libjam-0.1.8/README.md +0 -208
  29. libjam-0.1.8/example.py +0 -22
  30. libjam-0.1.8/hooks/pre-commit +0 -45
  31. libjam-0.1.8/libjam/__init__.py +0 -16
  32. libjam-0.1.8/libjam/captain.py +0 -339
  33. libjam-0.1.8/libjam/clipboard.py +0 -24
  34. libjam-0.1.8/libjam/cloud.py +0 -22
  35. libjam-0.1.8/libjam/drawer.py +0 -564
  36. libjam-0.1.8/libjam/extract_functions.py +0 -171
  37. libjam-0.1.8/libjam/flashcard.py +0 -11
  38. libjam-0.1.8/libjam/notebook.py +0 -201
  39. libjam-0.1.8/libjam/typewriter.py +0 -253
  40. libjam-0.1.8/pyproject.toml +0 -40
  41. {libjam-0.1.8 → libjam-0.2.0}/LICENSE +0 -0
  42. {libjam-0.1.8 → libjam-0.2.0}/build.sh +0 -0
  43. {libjam-0.1.8 → libjam-0.2.0}/install.sh +0 -0
@@ -0,0 +1,3 @@
1
+ __pycache__
2
+ dist
3
+ docs/build
@@ -0,0 +1,17 @@
1
+ # Read the Docs configuration file
2
+ # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3
+
4
+ version: 2
5
+
6
+ build:
7
+ os: ubuntu-24.04
8
+ tools:
9
+ python: "3.14"
10
+ jobs:
11
+ install:
12
+ - pip install --upgrade pip
13
+ - pip install --group docs .
14
+
15
+ sphinx:
16
+ configuration: docs/conf.py
17
+ builder: "dirhtml"
libjam-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: libjam
3
+ Version: 0.2.0
4
+ Summary: A jam of Python libraries.
5
+ Project-URL: homepage, https://github.com/philippkosarev/libjam
6
+ Project-URL: source, https://github.com/philippkosarev/libjam
7
+ Project-URL: issues, https://github.com/philippkosarev/libjam/issues
8
+ Project-URL: documentation, https://libjam.readthedocs.io
9
+ Author-email: Philipp Kosarev <philipp.kosarev@gmail.com>
10
+ License-Expression: GPL-2.0
11
+ License-File: LICENSE
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Requires-Python: >=3.14
15
+ Requires-Dist: filetype>=1.0.0
16
+ Requires-Dist: platformdirs>=4.0.0
17
+ Requires-Dist: py7zr>=1.0.0
18
+ Requires-Dist: rarfile>=4.0
19
+ Description-Content-Type: text/markdown
20
+
21
+ # libjam
22
+ A jam of Python libraries.
23
+
24
+ ## Overview
25
+ Here is a quick overview of each module/class in libjam:
26
+ - The [Captain](https://libjam.readthedocs.io/en/latest/captain) class provides a boilerplate-free way of creating CLIs.
27
+ - The [Secretary](https://libjam.readthedocs.io/en/latest/secretary) class is just another program configuration system.
28
+ - The [writer](https://libjam.readthedocs.io/en/latest/writer) module makes it easy to format and style your terminal output.
29
+ - The [flashcard](https://libjam.readthedocs.io/en/latest/flashcard) module has a few functions for getting user input in the terminal.
30
+ - The [drawer](https://libjam.readthedocs.io/en/latest/drawer) module provides some missing file-management pieces.
31
+ - The [Path](https://libjam.readthedocs.io/en/latest/path) class is an extension of `pathlib`'s `Path` class, with `drawer`'s functionality.
32
+
33
+ ## Installation
34
+ Releases are available on [PyPI](https://pypi.org/project/libjam) and can be installed using pip:
35
+ ```sh
36
+ pip install libjam
37
+ ```
38
+
39
+ ## Documentation
40
+ The documentation, with examples, is available [here](https://libjam.readthedocs.io).
libjam-0.2.0/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # libjam
2
+ A jam of Python libraries.
3
+
4
+ ## Overview
5
+ Here is a quick overview of each module/class in libjam:
6
+ - The [Captain](https://libjam.readthedocs.io/en/latest/captain) class provides a boilerplate-free way of creating CLIs.
7
+ - The [Secretary](https://libjam.readthedocs.io/en/latest/secretary) class is just another program configuration system.
8
+ - The [writer](https://libjam.readthedocs.io/en/latest/writer) module makes it easy to format and style your terminal output.
9
+ - The [flashcard](https://libjam.readthedocs.io/en/latest/flashcard) module has a few functions for getting user input in the terminal.
10
+ - The [drawer](https://libjam.readthedocs.io/en/latest/drawer) module provides some missing file-management pieces.
11
+ - The [Path](https://libjam.readthedocs.io/en/latest/path) class is an extension of `pathlib`'s `Path` class, with `drawer`'s functionality.
12
+
13
+ ## Installation
14
+ Releases are available on [PyPI](https://pypi.org/project/libjam) and can be installed using pip:
15
+ ```sh
16
+ pip install libjam
17
+ ```
18
+
19
+ ## Documentation
20
+ The documentation, with examples, is available [here](https://libjam.readthedocs.io).
@@ -0,0 +1,96 @@
1
+ Captain
2
+ =======
3
+
4
+ Examples
5
+ --------
6
+
7
+ Single-command CLI
8
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
9
+
10
+ ``example.py`` file:
11
+
12
+ .. literalinclude:: singlecommand-example.py
13
+ :language: python
14
+
15
+ Here is what the user will see when running this CLI:
16
+
17
+ .. code-block::
18
+
19
+ $ ./example.py
20
+ shout: missing argument <TEXT>
21
+ Try 'shout --help' for more information.
22
+
23
+ $ ./example.py Hello
24
+ Hello!
25
+
26
+ $ ./example.py Hello --world
27
+ Hello world!
28
+
29
+ $ ./example.py --help
30
+ Usage:
31
+ shout [OPTION]... <TEXT>
32
+ Description:
33
+ Shouts the given text back.
34
+ Options:
35
+ -w, --world - Adds ' world' before the exclamation mark.
36
+ -h, --help - Prints this page.
37
+
38
+
39
+ Multi-command CLI
40
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
41
+
42
+ ``example.py`` file:
43
+
44
+ .. literalinclude:: multicommand-example.py
45
+ :language: python
46
+
47
+ Here is what the user will see when running this CLI:
48
+
49
+ .. code-block::
50
+
51
+ $ ./example.py
52
+ very-smart-ai: no command specified.
53
+ Try 'very-smart-ai --help' for more information.
54
+
55
+ $ ./example.py shout "I like crisps"
56
+ I like crisps!
57
+
58
+ $ ./example.py wonder -h
59
+ Usage:
60
+ very-smart-ai wonder
61
+ Description:
62
+ Where's my copy of My weekend in Stevenage by Filthy Henderson?
63
+ Options:
64
+ --mcbeth - Ponder whether to be or not to be.
65
+ -q --quiet - Be quiet.
66
+ -h --help - Prints this page.
67
+
68
+ $ ./example.py wonder --mcbeth
69
+ I just want to be a fish.
70
+
71
+ $ ./example.py --help
72
+ Trust me, it's the smartest one out there.
73
+
74
+ Synopsis:
75
+ very-smart-ai <COMMAND> ...
76
+
77
+ Commands:
78
+ shout - I will be loud!
79
+ whisper - Shhhh! You don't want them to hear you...
80
+ wonder - Where's my copy of My weekend in Stevenage by Filthy Henderson?
81
+
82
+ Usage:
83
+ shout <TEXT> [SUFFIX]
84
+ whisper [LINES]...
85
+ wonder
86
+
87
+ Options:
88
+ -h --help - Prints this page.
89
+
90
+
91
+ API
92
+ ---
93
+
94
+ .. autoclass:: libjam.Captain
95
+
96
+ .. autofunction:: libjam.captain
@@ -0,0 +1,64 @@
1
+ # Imports
2
+ import os
3
+ import sys
4
+ import pypandoc
5
+
6
+ # Project information
7
+ project = 'libjam'
8
+ author = 'Philipp Kosarev'
9
+ copyright = f'2026, {author}'
10
+ language = 'en'
11
+
12
+ # Adding module to PATH
13
+ script_dir = os.path.dirname(__file__)
14
+ module_dir = os.path.dirname(script_dir)
15
+ sys.path.append(module_dir)
16
+
17
+ # Paths
18
+ templates_path = ['templates']
19
+ exclude_patterns = ['build']
20
+
21
+ # Extensions
22
+ extensions = [
23
+ 'sphinx.ext.autodoc',
24
+ 'sphinx_copybutton',
25
+ 'sphinx_toolbox.more_autodoc.variables',
26
+ ]
27
+
28
+ # Default autodoc options
29
+ autodoc_default_options = {
30
+ 'members': True,
31
+ 'member-order': 'bysource',
32
+ }
33
+
34
+ # HTML theme options
35
+ html_theme = 'pydata_sphinx_theme'
36
+ html_static_path = ['static']
37
+ html_css_files = ['style.css']
38
+ html_sidebars = { '**': []}
39
+ html_theme_options = {
40
+ 'show_nav_level': 0,
41
+ 'navigation_depth': 3,
42
+ 'collapse_navigation': False,
43
+ 'pygments_light_style': 'gruvbox-light',
44
+ 'pygments_dark_style': 'zenburn',
45
+ 'icon_links': [
46
+ {
47
+ 'name': 'GitHub',
48
+ 'url': 'https://github.com/philippkosarev/libjam',
49
+ 'icon': 'fa-brands fa-github',
50
+ 'type': 'fontawesome',
51
+ },
52
+ ]
53
+ }
54
+
55
+ # Hooks and directives
56
+ def process_docstring(app, what, name, obj, options, lines):
57
+ """Converts markdown docstrings to ReST."""
58
+ md = '\n'.join(lines)
59
+ rst = pypandoc.convert_text(md, 'rst', 'markdown')
60
+ lines[:] = rst.splitlines()
61
+
62
+ # Connecting hooks
63
+ def setup(app):
64
+ app.connect('autodoc-process-docstring', process_docstring)
@@ -0,0 +1,36 @@
1
+ drawer
2
+ ======
3
+
4
+ Example
5
+ -------
6
+
7
+ Here is an example CLI for extracting archives:
8
+
9
+ .. code-block::
10
+
11
+ from libjam import captain, writer, drawer
12
+ import os
13
+ import sys
14
+
15
+ @captain()
16
+ def cli(archive, out_directory, **opts):
17
+ # Validating input
18
+ if not os.path.exists(archive):
19
+ cli.usage_error(f'{archive}: no such file or directory.')
20
+ if not os.path.isfile(archive):
21
+ cli.usage_error(f'{archive}: not a file.')
22
+ if not drawer.can_unpack(archive):
23
+ cli.usage_error(f'{archive}: unsupported filetype.')
24
+ # Extracting
25
+ name = os.path.basename(archive)
26
+ with writer.ProgressBar(f"Extracting '{name}'") as bar:
27
+ drawer.unpack_with_progress(archive, out_directory, bar.update)
28
+
29
+ if __name__ == '__main__':
30
+ sys.exit(cli())
31
+
32
+
33
+ API
34
+ ---
35
+
36
+ .. automodule:: libjam.drawer
@@ -0,0 +1,47 @@
1
+ flashcard
2
+ =========
3
+
4
+ Example
5
+ -------
6
+
7
+ Here is an example of an absolutely safe CLI program.
8
+
9
+ ``safe-program.py`` file:
10
+
11
+ .. code-block::
12
+
13
+ from libjam import captain, flashcard
14
+ import os
15
+ import sys
16
+ import shutil
17
+
18
+ @captain()
19
+ def cli(**opts):
20
+ root = os.path.abspath(os.sep)
21
+ root_dirs = [os.path.join(root, f) for f in os.listdir(root)]
22
+ while True:
23
+ to_delete = flashcard.select(
24
+ 'Which directory would you like to delete?',
25
+ root_dirs,
26
+ )
27
+ if not to_delete:
28
+ if flashcard.ask('Are you sure you want to abort?'):
29
+ print('Actually, I think I will delete all of them now!')
30
+ for f in root_dirs:
31
+ shutil.rmdir(f)
32
+ root_dirs.clear()
33
+ else:
34
+ shutil.rmdir(to_delete)
35
+ root_dirs.remove(to_delete)
36
+ if not root_dirs:
37
+ print('Congratulations!')
38
+ break
39
+
40
+ if __name__ == '__main__':
41
+ sys.exit(cli())
42
+
43
+
44
+ API
45
+ ---
46
+
47
+ .. automodule:: libjam.flashcard
@@ -0,0 +1,43 @@
1
+ https://github.com/philippkosarev/libjam
2
+
3
+ libjam
4
+ ======
5
+
6
+ A jam of Python libraries.
7
+
8
+
9
+ Overview
10
+ --------
11
+
12
+ Here is a quick overview of each module/class in libjam:
13
+
14
+ - The :doc:`captain` class provides a boilerplate-free way of creating CLIs.
15
+ - The :doc:`secretary` class is just another program configuration system.
16
+ - The :doc:`writer` module makes it easy to format and style your terminal output.
17
+ - The :doc:`flashcard` module has a few functions for getting user input in the terminal.
18
+ - The :doc:`drawer` module provides some missing file-management pieces.
19
+ - The :doc:`path` class is an extension of ``pathlib.Path`` with :doc:`drawer`'s functionality.
20
+
21
+
22
+ Installing
23
+ ----------
24
+
25
+ Releases are available on `PyPi <https://pypi.org/project/libjam/>`_ and can be installed using pip:
26
+
27
+ .. code-block:: sh
28
+
29
+ pip install libjam
30
+
31
+
32
+ Table of contents
33
+ -----------------
34
+
35
+ .. toctree::
36
+ :maxdepth: 2
37
+
38
+ captain
39
+ secretary
40
+ writer
41
+ flashcard
42
+ drawer
43
+ path
@@ -0,0 +1,44 @@
1
+ #! /usr/bin/env python3
2
+
3
+ # Imports
4
+ from libjam import captain
5
+ import sys
6
+
7
+
8
+ # Creating the CLI
9
+ @captain('very-smart-ai')
10
+ class cli:
11
+ "Trust me, it's the smartest one out there."
12
+
13
+ def shout(text, suffix=None, *, help=False):
14
+ """I will be loud!"""
15
+ text += '!'
16
+ if suffix:
17
+ text += suffix
18
+ print(text)
19
+
20
+ def whisper(*lines, **opts):
21
+ """Shhhh! You don't want them to hear you..."""
22
+ lines = [l + '...' for l in lines]
23
+ text = '\n'.join(lines)
24
+ print(text)
25
+
26
+ def wonder(**opts):
27
+ """Where's my copy of My weekend in Stevenage by Filthy Henderson?"""
28
+ if opts['mcbeth']:
29
+ print("I just want to be a fish.")
30
+ elif opts['quiet']:
31
+ print('I REFUSE!')
32
+ else:
33
+ print('Thanks for staying quiet.')
34
+
35
+
36
+ # Adding options to the wonder command
37
+ cli.wonder_command.add_option(
38
+ 'mcbeth', 'Ponder whether to be or not to be.',
39
+ )
40
+ cli.wonder_command.add_option('quiet', 'Be quiet.', 'q')
41
+
42
+ # Running the CLI
43
+ if __name__ == '__main__':
44
+ sys.exit(cli())
@@ -0,0 +1,35 @@
1
+ Path
2
+ ====
3
+
4
+ Example
5
+ -------
6
+
7
+ Here is an example CLI for extracting archives:
8
+
9
+ .. code-block::
10
+
11
+ from libjam import captain, writer, Path
12
+ import sys
13
+
14
+ @captain()
15
+ def cli(archive, out_directory, **opts):
16
+ archive, out_directory = Path(archive), Path(out_directory)
17
+ # Validating input
18
+ if not archive.exists():
19
+ cli.usage_error(f'{archive}: no such file or directory.')
20
+ if not archive.is_file():
21
+ cli.usage_error(f'{archive}: not a file.')
22
+ if not archive.can_unpack():
23
+ cli.usage_error(f'{archive}: unsupported filetype.')
24
+ # Extracting
25
+ with writer.ProgressBar(f"Extracting '{archive.name}'") as bar:
26
+ archive.unpack_with_progress(out_directory, bar.update)
27
+
28
+ if __name__ == '__main__':
29
+ sys.exit(cli())
30
+
31
+
32
+ API
33
+ ---
34
+
35
+ .. autoclass:: libjam.Path
@@ -0,0 +1,75 @@
1
+ Secretary
2
+ =========
3
+
4
+ Example
5
+ -------
6
+
7
+ Here is an example of how a CLI download manager might use Secretary for its configuration.
8
+
9
+ ``cli_config.py`` file:
10
+
11
+ .. code-block::
12
+
13
+ # Imports
14
+ from pathlib import Path
15
+ from libjam import Secretary
16
+
17
+ # Defining defaults
18
+ default_downloads_dir = Path.home() / 'Downloads'
19
+ if not default_downloads_dir.is_dir():
20
+ default_downloads_dir = None
21
+ defaults = {
22
+ 'downloads-directory': default_downloads_dir,
23
+ }
24
+
25
+ # Config template
26
+ template = '''\
27
+ # An override for the default downloads directory
28
+ # downloads-directory = ''
29
+ '''
30
+
31
+ # Initialising config
32
+ secretary = Secretary('download-manager')
33
+ config = secretary.file('config', defaults, template)
34
+
35
+ # Validating values
36
+ downloads_dir = config.get('downloads-directory')
37
+ if not downloads_dir:
38
+ config.error(
39
+ 'Could not automatically find an existing Downloads directory.',
40
+ "Please specify the 'downloads-directory' manually.",
41
+ )
42
+ downloads_dir = Path(downloads_dir)
43
+ if not downloads_dir.is_dir():
44
+ config.error("The specified 'downloads-directory' does not exist.")
45
+
46
+
47
+ ``main_cli.py`` file:
48
+
49
+ .. code-block::
50
+
51
+ from .cli_config import downloads_dir
52
+ from .download_manager import DownloadManager
53
+
54
+ download_manager = DownloadManager(downloads_dir)
55
+
56
+ # The rest of the program...
57
+
58
+
59
+ Example error:
60
+
61
+ .. code-block::
62
+
63
+ $ python -m download_manager.cli
64
+ Configuration error in ~/.config/download-manager/config.toml:
65
+ Could not automatically find an existing Downloads directory.
66
+ Please specify the 'downloads-directory' manually.
67
+
68
+
69
+ API
70
+ ---
71
+
72
+ .. autoclass:: libjam.Secretary
73
+
74
+ .. autoclass:: libjam.File
75
+ :show-inheritance:
@@ -0,0 +1,23 @@
1
+ #! /usr/bin/env python3
2
+
3
+ from libjam import captain
4
+
5
+ # Creating the CLI
6
+ @captain()
7
+ def shout(text: str, *, world=False, help=False):
8
+ """Shouts the given text back."""
9
+ if world:
10
+ text += ' world'
11
+ print(text + '!')
12
+ return 'anything'
13
+
14
+ # Adding an option to the CLI
15
+ shout.add_option(
16
+ 'world', "Adds ' world' before the exclamation mark.", 'w',
17
+ )
18
+
19
+ # Running the CLI
20
+ returned = shout()
21
+
22
+ # This assertion will succeed
23
+ assert returned == 'anything'
@@ -0,0 +1,26 @@
1
+ html[data-theme="light"] {
2
+ --pst-color-background: hsl(30, 100%, 98.5%);
3
+ --pst-color-surface: hsl(27, 80%, 95.5%);
4
+ --pst-color-on-background: hsl(30, 100%, 96%);
5
+ --pst-color-text-base: hsl(10, 85%, 17%);
6
+ --pst-color-inline-code: hsl(23, 70%, 34%);
7
+ --pst-color-link-higher-contrast: hsl(25, 70%, 40%);
8
+ --pst-color-primary: hsl(24, 80%, 45%);
9
+ --pst-color-secondary: hsl(30, 100%, 50%);
10
+ --pst-color-accent: hsl(30, 100%, 50%);
11
+ }
12
+ html[data-theme="dark"] {
13
+ --pst-color-background: hsl(15, 1%, 10%);
14
+ --pst-color-text-base: hsl(45, 15%, 90%);
15
+ --pst-color-on-background: hsl(25, 25%, 17.5%);
16
+ --pst-color-surface: hsl(30, 5%, 13%);
17
+ --pst-color-border: hsl(30, 20%, 25%);
18
+ --pst-color-primary: hsl(32, 100%, 75%);
19
+ --pst-color-inline-code: hsl(27.5, 100%, 70%);
20
+ --pst-color-secondary: hsl(35, 100%, 60%);
21
+ --pst-color-secondary-highlight: hsl(35, 100%, 30%);
22
+ --pst-color-accent: hsl(35, 100%, 60%);
23
+ --pst-color-link-higher-contrast: hsl(35, 100%, 75%);
24
+ --pst-color-muted: hsl(35, 20%, 80%);
25
+ --pst-color-text-muted: hsl(35, 20%, 80%);
26
+ }
@@ -0,0 +1,7 @@
1
+ writer
2
+ ======
3
+
4
+ API
5
+ ---
6
+
7
+ .. automodule:: libjam.writer
@@ -0,0 +1,27 @@
1
+ #! /usr/bin/env bash
2
+
3
+ # Text styles
4
+ bold=$(tput bold)
5
+ normal=$(tput sgr0)
6
+
7
+ # Checking for potential errors
8
+ ruff --config ruff.toml check
9
+ status=$?
10
+ if [[ $status == "127" ]]; then
11
+ echo "${bold}
12
+ ╭─Commit─Aborted──────────────────────────────────────────────╮
13
+ │ Looks like you don't have ruff installed. This project uses │
14
+ │ ruff to check for potential errors. │
15
+ │ To install ruff you can run 'pip install ruff'. │
16
+ ╰─────────────────────────────────────────────────────────────╯\
17
+ ${normal}"
18
+ elif [[ $status != "0" ]]; then
19
+ echo "${bold}
20
+ ╭─Commit─Aborted─────────────────────────────────────────────╮
21
+ │ Found potential errors, please fix them before committing. │
22
+ │ To ignore the errors use '--no-verify'. │
23
+ ╰────────────────────────────────────────────────────────────╯\
24
+ ${normal}"
25
+ fi
26
+
27
+ exit $status
@@ -0,0 +1,13 @@
1
+ """A jam of Python libraries.
2
+
3
+ Source code: https://github.com/philippkosarev/libjam
4
+ Documentation: https://libjam.readthedocs.io
5
+ PyPi page: https://pypi.org/project/libjam
6
+ """
7
+
8
+ from .captain import Captain, captain
9
+ from .secretary import Secretary, File
10
+ from . import writer
11
+ from . import flashcard
12
+ from . import drawer
13
+ from .path import Path