Compare commits
No commits in common. "6bb188f970a1d2a51a0f9f7e0a9ca9a7bbab7772" and "68987d4118b4670f0def1d00db9645b30525d733" have entirely different histories.
6bb188f970
...
68987d4118
|
@ -66,46 +66,6 @@ optional = false
|
||||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
|
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Optional static typing for Python"
|
|
||||||
name = "mypy"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
version = "0.800"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
mypy-extensions = ">=0.4.3,<0.5.0"
|
|
||||||
typed-ast = ">=1.4.0,<1.5.0"
|
|
||||||
typing-extensions = ">=3.7.4"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
dmypy = ["psutil (>=4.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Experimental type system extensions for programs checked with the mypy typechecker."
|
|
||||||
name = "mypy-extensions"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.4.3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "a fork of Python 2 and 3 ast modules with type comment support"
|
|
||||||
name = "typed-ast"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "1.4.2"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Backported and Experimental Type Hints for Python 3.5+"
|
|
||||||
name = "typing-extensions"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "3.7.4.3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "main"
|
category = "main"
|
||||||
description = "The comprehensive WSGI web application library."
|
description = "The comprehensive WSGI web application library."
|
||||||
|
@ -119,7 +79,7 @@ dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-
|
||||||
watchdog = ["watchdog"]
|
watchdog = ["watchdog"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
content-hash = "27f45d27293b2411af59f2d60572508a045af3d996d09cd45001f73388f721fd"
|
content-hash = "b9f532f610ddec69914e59c13e5dc4b49e8d5a89a6365c4e32bfaea736dae4c8"
|
||||||
lock-version = "1.0"
|
lock-version = "1.0"
|
||||||
python-versions = "^3.8"
|
python-versions = "^3.8"
|
||||||
|
|
||||||
|
@ -179,71 +139,6 @@ markupsafe = [
|
||||||
{file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"},
|
{file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"},
|
||||||
{file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
|
{file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
|
||||||
]
|
]
|
||||||
mypy = [
|
|
||||||
{file = "mypy-0.800-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:e1c84c65ff6d69fb42958ece5b1255394714e0aac4df5ffe151bc4fe19c7600a"},
|
|
||||||
{file = "mypy-0.800-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:947126195bfe4709c360e89b40114c6746ae248f04d379dca6f6ab677aa07641"},
|
|
||||||
{file = "mypy-0.800-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:b95068a3ce3b50332c40e31a955653be245666a4bc7819d3c8898aa9fb9ea496"},
|
|
||||||
{file = "mypy-0.800-cp35-cp35m-win_amd64.whl", hash = "sha256:ca7ad5aed210841f1e77f5f2f7d725b62c78fa77519312042c719ed2ab937876"},
|
|
||||||
{file = "mypy-0.800-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e32b7b282c4ed4e378bba8b8dfa08e1cfa6f6574067ef22f86bee5b1039de0c9"},
|
|
||||||
{file = "mypy-0.800-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e497a544391f733eca922fdcb326d19e894789cd4ff61d48b4b195776476c5cf"},
|
|
||||||
{file = "mypy-0.800-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:5615785d3e2f4f03ab7697983d82c4b98af5c321614f51b8f1034eb9ebe48363"},
|
|
||||||
{file = "mypy-0.800-cp36-cp36m-win_amd64.whl", hash = "sha256:2b216eacca0ec0ee124af9429bfd858d5619a0725ee5f88057e6e076f9eb1a7b"},
|
|
||||||
{file = "mypy-0.800-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e3b8432f8df19e3c11235c4563a7250666dc9aa7cdda58d21b4177b20256ca9f"},
|
|
||||||
{file = "mypy-0.800-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d16c54b0dffb861dc6318a8730952265876d90c5101085a4bc56913e8521ba19"},
|
|
||||||
{file = "mypy-0.800-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0d2fc8beb99cd88f2d7e20d69131353053fbecea17904ee6f0348759302c52fa"},
|
|
||||||
{file = "mypy-0.800-cp37-cp37m-win_amd64.whl", hash = "sha256:aa9d4901f3ee1a986a3a79fe079ffbf7f999478c281376f48faa31daaa814e86"},
|
|
||||||
{file = "mypy-0.800-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:319ee5c248a7c3f94477f92a729b7ab06bf8a6d04447ef3aa8c9ba2aa47c6dcf"},
|
|
||||||
{file = "mypy-0.800-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:74f5aa50d0866bc6fb8e213441c41e466c86678c800700b87b012ed11c0a13e0"},
|
|
||||||
{file = "mypy-0.800-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:a301da58d566aca05f8f449403c710c50a9860782148332322decf73a603280b"},
|
|
||||||
{file = "mypy-0.800-cp38-cp38-win_amd64.whl", hash = "sha256:b9150db14a48a8fa114189bfe49baccdff89da8c6639c2717750c7ae62316738"},
|
|
||||||
{file = "mypy-0.800-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5fdf935a46aa20aa937f2478480ebf4be9186e98e49cc3843af9a5795a49a25"},
|
|
||||||
{file = "mypy-0.800-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6f8425fecd2ba6007e526209bb985ce7f49ed0d2ac1cc1a44f243380a06a84fb"},
|
|
||||||
{file = "mypy-0.800-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:5ff616787122774f510caeb7b980542a7cc2222be3f00837a304ea85cd56e488"},
|
|
||||||
{file = "mypy-0.800-cp39-cp39-win_amd64.whl", hash = "sha256:90b6f46dc2181d74f80617deca611925d7e63007cf416397358aa42efb593e07"},
|
|
||||||
{file = "mypy-0.800-py3-none-any.whl", hash = "sha256:3e0c159a7853e3521e3f582adb1f3eac66d0b0639d434278e2867af3a8c62653"},
|
|
||||||
{file = "mypy-0.800.tar.gz", hash = "sha256:e0202e37756ed09daf4b0ba64ad2c245d357659e014c3f51d8cd0681ba66940a"},
|
|
||||||
]
|
|
||||||
mypy-extensions = [
|
|
||||||
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
|
|
||||||
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
|
|
||||||
]
|
|
||||||
typed-ast = [
|
|
||||||
{file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"},
|
|
||||||
{file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"},
|
|
||||||
{file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"},
|
|
||||||
{file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"},
|
|
||||||
{file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"},
|
|
||||||
{file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"},
|
|
||||||
{file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"},
|
|
||||||
{file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"},
|
|
||||||
{file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"},
|
|
||||||
{file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"},
|
|
||||||
{file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"},
|
|
||||||
{file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"},
|
|
||||||
{file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"},
|
|
||||||
{file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"},
|
|
||||||
{file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"},
|
|
||||||
{file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"},
|
|
||||||
{file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"},
|
|
||||||
{file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"},
|
|
||||||
{file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"},
|
|
||||||
{file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"},
|
|
||||||
{file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"},
|
|
||||||
{file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"},
|
|
||||||
{file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"},
|
|
||||||
{file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"},
|
|
||||||
{file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"},
|
|
||||||
{file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"},
|
|
||||||
{file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"},
|
|
||||||
{file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"},
|
|
||||||
{file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"},
|
|
||||||
{file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"},
|
|
||||||
]
|
|
||||||
typing-extensions = [
|
|
||||||
{file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"},
|
|
||||||
{file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"},
|
|
||||||
{file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"},
|
|
||||||
]
|
|
||||||
werkzeug = [
|
werkzeug = [
|
||||||
{file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},
|
{file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},
|
||||||
{file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"},
|
{file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"},
|
||||||
|
|
|
@ -10,11 +10,10 @@ flask = "^1.1.2"
|
||||||
flask-login = "^0.5.0"
|
flask-login = "^0.5.0"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
mypy = "^0.800"
|
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poetry.scripts]
|
||||||
redstring-check = "redstring.parser:main"
|
|
||||||
redstring-server = "redstring.server:main"
|
redstring-server = "redstring.server:main"
|
||||||
|
redstring-cli = "redstring.parser:main"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry>=0.12"]
|
requires = ["poetry>=0.12"]
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
import redstring.parser
|
|
||||||
import redstring.server
|
|
|
@ -1,290 +1,3 @@
|
||||||
"""
|
def main():
|
||||||
Logic for reading and writing documents from files.
|
print("Hello, world!")
|
||||||
"""
|
print(__name__)
|
||||||
import argparse
|
|
||||||
from collections import OrderedDict
|
|
||||||
import json
|
|
||||||
from typing import Any, List, IO
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Types
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
class TabOptions:
|
|
||||||
"""
|
|
||||||
Display options for tabs.
|
|
||||||
"""
|
|
||||||
_PRIORITY_KEY = 'priority'
|
|
||||||
_HIDE_NAMES_KEY = 'hide_names'
|
|
||||||
_PRIVATE_KEY = 'private'
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
self.options: dict = OrderedDict(**kwargs)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def priority(self) -> int:
|
|
||||||
"""Priority determines tab order."""
|
|
||||||
return self.options.get(self._PRIORITY_KEY, 0)
|
|
||||||
|
|
||||||
@priority.setter
|
|
||||||
def priority(self, value: int):
|
|
||||||
self.options[self._PRIORITY_KEY] = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def hide_names(self) -> bool:
|
|
||||||
"""Hide the tag name column in the web view."""
|
|
||||||
return self.options.get(self._HIDE_NAMES_KEY, False)
|
|
||||||
|
|
||||||
@hide_names.setter
|
|
||||||
def hide_names(self, value: bool):
|
|
||||||
self.options[self._HIDE_NAMES_KEY] = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def private(self) -> bool:
|
|
||||||
"""Hide the tab from unauthenticated viewers."""
|
|
||||||
return self.options.get(self._PRIVATE_KEY, False)
|
|
||||||
|
|
||||||
@private.setter
|
|
||||||
def private(self, value: bool):
|
|
||||||
self.options[self._PRIVATE_KEY] = value
|
|
||||||
|
|
||||||
|
|
||||||
class TagOptions:
|
|
||||||
"""
|
|
||||||
Display options for tags.
|
|
||||||
"""
|
|
||||||
_HYPERLINK_KEY = 'hyperlink'
|
|
||||||
_INTERLINK_KEY = 'interlink'
|
|
||||||
_PRIVATE_KEY = 'private'
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
self.options = OrderedDict(**kwargs)
|
|
||||||
# Tag value is a hyperlink
|
|
||||||
self.hyperlink: bool = kwargs.get('hyperlink', False)
|
|
||||||
# Tag value contains redstring interlinks
|
|
||||||
self.interlink: bool = kwargs.get('interlink', False)
|
|
||||||
# Hide the tag from unauthenticated viewers
|
|
||||||
self.private: bool = kwargs.get('private', False)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def hyperlink(self) -> bool:
|
|
||||||
return self.options.get(self._HYPERLINK_KEY, False)
|
|
||||||
|
|
||||||
@hyperlink.setter
|
|
||||||
def hyperlink(self, value: bool):
|
|
||||||
self.options[self._HYPERLINK_KEY] = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def interlink(self) -> bool:
|
|
||||||
return self.options.get(self._INTERLINK_KEY, False)
|
|
||||||
|
|
||||||
@hyperlink.setter
|
|
||||||
def interlink(self, value: bool):
|
|
||||||
self.options[self._INTERLINK_KEY] = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def private(self) -> bool:
|
|
||||||
"""Hide the tab from unauthenticated viewers."""
|
|
||||||
return self.options.get(self._PRIVATE_KEY, False)
|
|
||||||
|
|
||||||
@private.setter
|
|
||||||
def private(self, value: bool):
|
|
||||||
self.options[self._PRIVATE_KEY] = value
|
|
||||||
|
|
||||||
|
|
||||||
class DocumentSubtag:
|
|
||||||
"""
|
|
||||||
A keyvalue describing a document subject.
|
|
||||||
"""
|
|
||||||
def __init__(self, name: str, value: str, options: TagOptions) -> None:
|
|
||||||
self.name: str = name
|
|
||||||
self.value: str = value
|
|
||||||
self.options: TagOptions = options
|
|
||||||
|
|
||||||
|
|
||||||
class DocumentTag:
|
|
||||||
"""
|
|
||||||
A keyvalue describing a document subject. It may have subtags.
|
|
||||||
"""
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
value: str,
|
|
||||||
options: TagOptions,
|
|
||||||
subtags: List[DocumentSubtag]
|
|
||||||
) -> None:
|
|
||||||
self.name: str = name
|
|
||||||
self.value = value
|
|
||||||
self.options = options
|
|
||||||
self.subtags = subtags
|
|
||||||
|
|
||||||
|
|
||||||
class DocumentTab:
|
|
||||||
"""
|
|
||||||
A division of tags within a document.
|
|
||||||
"""
|
|
||||||
def __init__(self, name: str, tags: List[DocumentTag], options: TabOptions) -> None:
|
|
||||||
self.tags: List[DocumentTag] = tags
|
|
||||||
self.options: TabOptions = options
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return self.tags.__iter__()
|
|
||||||
|
|
||||||
|
|
||||||
class Document:
|
|
||||||
"""
|
|
||||||
Top-level document definition.
|
|
||||||
"""
|
|
||||||
def __init__(self, tabs: List[DocumentTab]) -> None:
|
|
||||||
self.tabs: List[DocumentTab] = tabs
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return self.tabs.__iter__()
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Parsing functions
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
def load(fd: IO) -> Document:
|
|
||||||
"""
|
|
||||||
Load a document from a file descriptor.
|
|
||||||
"""
|
|
||||||
parsed_json = json.load(fd, object_pairs_hook=OrderedDict)
|
|
||||||
if not isinstance(parsed_json, list):
|
|
||||||
raise ValueError('Parsing as document, expected list')
|
|
||||||
return parse_document_from_json(parsed_json)
|
|
||||||
|
|
||||||
|
|
||||||
def loads(string: str) -> Document:
|
|
||||||
"""
|
|
||||||
Load a document from a string.
|
|
||||||
"""
|
|
||||||
parsed_json = json.loads(string, object_pairs_hook=OrderedDict)
|
|
||||||
if not isinstance(parsed_json, list):
|
|
||||||
raise ValueError('Parsing as document, expected list')
|
|
||||||
return parse_document_from_json(parsed_json)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_document_from_json(parsed_json: list) -> Document:
|
|
||||||
"""
|
|
||||||
Parses JSON into a Document object.
|
|
||||||
"""
|
|
||||||
# Parse tabs
|
|
||||||
tabs: List[DocumentTab] = []
|
|
||||||
for tab_json in parsed_json:
|
|
||||||
if not isinstance(tab_json, dict):
|
|
||||||
raise ValueError(f'Parsing tab, expected dict but got {type(tab_json)}')
|
|
||||||
tabs.append(parse_tab_from_json(tab_json))
|
|
||||||
|
|
||||||
return Document(tabs)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_tab_from_json(tab_json: dict) -> DocumentTab:
|
|
||||||
"""
|
|
||||||
Parses JSON into a DocumentTab object.
|
|
||||||
"""
|
|
||||||
# Parse tab name
|
|
||||||
if 'name' not in tab_json:
|
|
||||||
raise ValueError('Expected tab name')
|
|
||||||
name: str = tab_json['name']
|
|
||||||
|
|
||||||
# Parse tab options
|
|
||||||
options_json: dict = {}
|
|
||||||
if 'options' in tab_json:
|
|
||||||
options_json = tab_json['options']
|
|
||||||
options: TabOptions = TabOptions(**options_json)
|
|
||||||
|
|
||||||
# Parse tags
|
|
||||||
tags: List[DocumentTag] = []
|
|
||||||
if 'tags' in tab_json:
|
|
||||||
tags_json: list = tab_json['tags']
|
|
||||||
for tag_json in tags_json:
|
|
||||||
if not isinstance(tag_json, dict):
|
|
||||||
raise ValueError(f'Parsing tag, expected dict but got {type(tag_json)}')
|
|
||||||
tags.append(parse_tag_from_json(tag_json))
|
|
||||||
|
|
||||||
return DocumentTab(name, tags, options)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_tag_from_json(tag_json: dict) -> DocumentTag:
|
|
||||||
"""
|
|
||||||
Parses JSON into a DocumentTag object.
|
|
||||||
"""
|
|
||||||
# Parse name
|
|
||||||
if 'name' not in tag_json:
|
|
||||||
raise ValueError('Expected tag name')
|
|
||||||
name: str = tag_json['name']
|
|
||||||
|
|
||||||
# Parse value
|
|
||||||
value: str = ''
|
|
||||||
if 'value' in tag_json:
|
|
||||||
value = tag_json['value']
|
|
||||||
|
|
||||||
# Parse tag options
|
|
||||||
options_json: dict = {}
|
|
||||||
if 'options' in tag_json:
|
|
||||||
options_json = tag_json['options']
|
|
||||||
options: TagOptions = TagOptions(**options_json)
|
|
||||||
|
|
||||||
# Parse subtags
|
|
||||||
subtags: List[DocumentSubtag] = []
|
|
||||||
if 'subtags' in tag_json:
|
|
||||||
subtags_json: list = tag_json['subtags']
|
|
||||||
for subtag_json in subtags_json:
|
|
||||||
if not isinstance(subtag_json, dict):
|
|
||||||
raise ValueError(f'Parsing subtag, expected dict but got {type(subtag_json)}')
|
|
||||||
subtags.append(parse_subtag_from_json(subtag_json))
|
|
||||||
|
|
||||||
return DocumentTag(name, value, options, subtags)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_subtag_from_json(subtag_json: dict) -> DocumentSubtag:
|
|
||||||
"""
|
|
||||||
Parses JSON into a DocumentSubtag object.
|
|
||||||
"""
|
|
||||||
# Parse name
|
|
||||||
if 'name' not in subtag_json:
|
|
||||||
raise ValueError('Expected subtag name')
|
|
||||||
name: str = subtag_json['name']
|
|
||||||
|
|
||||||
# Parse value
|
|
||||||
value: str = ''
|
|
||||||
if 'value' in subtag_json:
|
|
||||||
value = subtag_json['value']
|
|
||||||
|
|
||||||
# Parse tag options
|
|
||||||
options_json: dict = {}
|
|
||||||
if 'options' in subtag_json:
|
|
||||||
options_json = subtag_json['options']
|
|
||||||
options: TagOptions = TagOptions(**options_json)
|
|
||||||
|
|
||||||
return DocumentSubtag(name, value, options)
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# CLI functions
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
def check(files):
|
|
||||||
"""
|
|
||||||
Checks a list of files for syntactical validity.
|
|
||||||
"""
|
|
||||||
for file in files:
|
|
||||||
with open(file) as f:
|
|
||||||
try:
|
|
||||||
load(f)
|
|
||||||
print(f'OK {file}')
|
|
||||||
except Exception as ex:
|
|
||||||
print(f'ERROR {file} - {ex}')
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> Any:
|
|
||||||
parser = argparse.ArgumentParser(description='Test a serialized redstring document file for validity.')
|
|
||||||
parser.add_argument('file', nargs='+', help='Files to check')
|
|
||||||
args = parser.parse_args()
|
|
||||||
check(args.file)
|
|
||||||
|
|
Loading…
Reference in New Issue