From df8470bf9d61b70691ea61a3df0969ea6a50d95b Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Sat, 24 Oct 2020 21:41:40 -0500 Subject: [PATCH] LiraApp: load books from config file --- lira/__main__.py | 10 +++-- lira/app.py | 67 +++++++++++++++++++++++++++- lira/books/__init__.py | 0 lira/books/intro/__init__.py | 0 lira/books/intro/book.yaml | 11 +++++ lira/books/intro/intro.rst | 12 +++++ lira/books/intro/showcase.rst | 12 +++++ lira/config.py | 1 + noxfile.py | 2 +- setup.py | 5 +++ tests/data/books/config.yaml | 3 ++ tests/data/books/example/__init__.py | 0 tests/test_app.py | 29 ++++++++++++ 13 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 lira/books/__init__.py create mode 100644 lira/books/intro/__init__.py create mode 100644 lira/books/intro/book.yaml create mode 100644 lira/books/intro/intro.rst create mode 100644 lira/books/intro/showcase.rst create mode 100644 tests/data/books/config.yaml create mode 100644 tests/data/books/example/__init__.py create mode 100644 tests/test_app.py diff --git a/lira/__main__.py b/lira/__main__.py index 985451b..667966d 100644 --- a/lira/__main__.py +++ b/lira/__main__.py @@ -2,7 +2,11 @@ from lira.ui import TerminalUI -books_path = Path(__file__).parent / "../tests/data/books/example/" -ui = TerminalUI(books_path) -ui.run() +def main(): + books_path = Path(__file__).parent / "../tests/data/books/example/" + ui = TerminalUI(books_path) + ui.run() + + +main() diff --git a/lira/app.py b/lira/app.py index d29b06f..6d9424b 100644 --- a/lira/app.py +++ b/lira/app.py @@ -1,6 +1,13 @@ +import importlib import logging +from pathlib import Path -from lira.config import CONFIG_DIR, DATA_DIR, LOG_DIR +import yaml + +from lira.book import Book +from lira.config import CONFIG_DIR, CONFIG_FILE, DATA_DIR, LOG_DIR + +log = logging.getLogger(__name__) class LiraApp: @@ -17,6 +24,64 @@ def _setup_logger(self): level=logging.WARNING, ) + def _read_config(self): + if not CONFIG_FILE.exists(): + log.info("Config file not found") + return {} + with CONFIG_FILE.open() as f: + config = yaml.safe_load(f) + return config + + @property + def books(self): + """ + Load all books from the Lira configuration file. + + Each book can be a dotted path to the module of the book, + or a local path to the directory of the book + (it can be a relative path to the config file). + + .. code-block:: yaml + books: + # A dotted path to the module + - lira.books.intro + + # A local path + - ~/local/path/to/book/ + + # A relative path to the config file + - relative/path + + # Install from a package (maybe in the future) + - name: lira.book.basic + package: git+https://gifhub.com/pythonecuador/pythones-lirabook + - name: lira.book.basic + package: pythones-lirabook + """ + config = self._read_config() + books_list = [] + for book_path in config.get("books", ["lira.books.intro"]): + path = Path(book_path).expanduser() + if not path.is_absolute(): + path = (CONFIG_FILE.parent / path).resolve() + + if path.exists() and path.is_dir(): + books_list.append(Book(root=path)) + else: + try: + package = importlib.import_module(book_path) + path = Path(package.__file__).parent + books_list.append(Book(root=path)) + except ModuleNotFoundError: + log.warning("Unable to find book: %s", book_path) + except Exception as e: + log.warning( + "Unable to load book. path=%s error=%s", + book_path, + str(e), + ) + return books_list + def setup(self): self._create_dirs() self._setup_logger() diff --git a/lira/books/__init__.py b/lira/books/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lira/books/intro/__init__.py b/lira/books/intro/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lira/books/intro/book.yaml b/lira/books/intro/book.yaml new file mode 100644 index 0000000..0e3c8f7 --- /dev/null +++ b/lira/books/intro/book.yaml @@ -0,0 +1,11 @@ +language: en +title: Intro to Lira +description: Introducction to Lira and how to write a Lira book +created: 24/10/2020 +updated: 24/10/2020 +authors: + - Santos Gallegos + +contents: + Introducction: intro.rst + Showcase: showcase.rst diff --git a/lira/books/intro/intro.rst b/lira/books/intro/intro.rst new file mode 100644 index 0000000..7f4f972 --- /dev/null +++ b/lira/books/intro/intro.rst @@ -0,0 +1,12 @@ +:level: easy +:tags: lira book + +Lira +---- + +Lira is an interactive tutorial. + +Writting a book +--------------- + +TODO diff --git a/lira/books/intro/showcase.rst b/lira/books/intro/showcase.rst new file mode 100644 index 0000000..8f16d98 --- /dev/null +++ b/lira/books/intro/showcase.rst @@ -0,0 +1,12 @@ +:level: easy +:tags: showcase book + +Basic elements +-------------- + +This is a paragraph with *some* nodes. +I'm a ``literal`` node, and I'm **strong**. + +.. code-block:: python + + print("Hello world!") diff --git a/lira/config.py b/lira/config.py index 0adb66f..7b82de5 100644 --- a/lira/config.py +++ b/lira/config.py @@ -25,5 +25,6 @@ def _get_data_dir(): CONFIG_DIR = _get_config_dir() +CONFIG_FILE = CONFIG_DIR / "config.yaml" DATA_DIR = _get_data_dir() LOG_DIR = DATA_DIR / "log" diff --git a/noxfile.py b/noxfile.py index ab0eeb2..e1699c6 100644 --- a/noxfile.py +++ b/noxfile.py @@ -19,7 +19,7 @@ def tests(session): @nox.session def coverage(session): session.install("coverage") - session.run("coverage", "report", "--fail-under", "79") + session.run("coverage", "report", "--fail-under", "84") session.run("coverage", "html") diff --git a/setup.py b/setup.py index 484b093..b285ed3 100644 --- a/setup.py +++ b/setup.py @@ -19,6 +19,11 @@ "PyYAML==5.3.1", "prompt-toolkit==3.0.7", ], + entry_points={ + "console_scripts": [ + "lira=lira.__main__:main", + ], + }, extras_require={"docs": ["sphinx==3.2.1"], "es": []}, classifiers=[ "Programming Language :: Python :: 3", diff --git a/tests/data/books/config.yaml b/tests/data/books/config.yaml new file mode 100644 index 0000000..c2653d8 --- /dev/null +++ b/tests/data/books/config.yaml @@ -0,0 +1,3 @@ +books: + - lira.books.intro + - example/ diff --git a/tests/data/books/example/__init__.py b/tests/data/books/example/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_app.py b/tests/test_app.py new file mode 100644 index 0000000..8afd6a7 --- /dev/null +++ b/tests/test_app.py @@ -0,0 +1,29 @@ +from pathlib import Path +from unittest import mock + +from lira.app import LiraApp + +data_dir = Path(__file__).parent / "data" +config_file = data_dir / "books/config.yaml" + + +class TestApp: + @mock.patch("lira.app.CONFIG_FILE", config_file) + def test_load_books(self): + app = LiraApp() + app.setup() + + books = app.books + assert len(books) == 2 + + book_a, book_b = books + book_a.parse() + book_b.parse() + + assert book_a.metadata["title"] == "Intro to Lira" + book_path = data_dir / "../../lira/books/intro" + assert book_a.root == book_path.resolve() + + assert book_b.metadata["title"] == "Basic Introducction to Python" + book_path = data_dir / "books/example" + assert book_b.root == book_path