Fin de refactorización

This commit is contained in:
perro tuerto 2023-01-27 12:19:39 -08:00
parent 9db7d96a06
commit fdd44d72ff
1 changed files with 174 additions and 89 deletions

263
yasd.py
View File

@ -16,7 +16,14 @@ class YASD:
YASD actions performer.
"""
def do(action="check", indata=None, outfile=None, quiet=False, log=False):
def do(
action="check",
indata=None,
outfile=None,
quiet=False,
log=False,
stdout=False,
):
"""
Performs YASD actions directly.
@ -31,17 +38,27 @@ class YASD:
:type quiet: True or False
:param log: If messages are write in a file or not; 'False' by default
:type log: True or False
:param stdout: if conversion goes to stdout or not; 'False' by default
:type stdout: True or False
:return: Output data; str on 'document'; bs4.element.Tag on 'convert'
or 'sample'; YAML dict on 'check'
:rtype: str or bs4.element.Tag or dict
"""
yasd = YASD(indata, outfile, quiet, log)
yasd = YASD(indata, outfile, quiet, log, stdout)
yasd.msgr.run(f"action_{action}")
if action == "convert":
yasd.convert(stdout=True)
elif action == "sample":
yasd.sample(stdout=True)
elif action == "document":
yasd.document(stdout=True)
match action:
case "document":
return yasd.document()
case "convert":
return yasd.convert()
case "sample":
return yasd.sample()
case "check":
return yasd.yaml
def __init__(self, indata=None, outfile=None, quiet=False, log=False):
def __init__(
self, indata=None, outfile=None, quiet=False, log=False, stdout=False
):
"""
Inits YASD object.
@ -55,56 +72,83 @@ class YASD:
:type log: True or False
"""
self.msgr = YASDMessenger(quiet=quiet, log=log)
self.outfile = YASDCheck.file(outfile, self.msgr)
self.yaml = YASDCheck(indata, self.msgr).yaml
self.formatter = XMLFormatter(indent=2)
self.outfile = outfile
self.xsd = None
self.out = ""
self.stdout = stdout
def convert(self, stdout=False):
def convert(self):
"""
Converts YASD to XSD.
:param stdout: if conversion goes to stdout or not; 'False' by default
:type stdout: True or False
:return: XSD element
:rtype: bs4.element.Tag
"""
self.xsd = YASDXSD(self.yaml, self.msgr).xsd
return self.__output(self.xsd)
def sample(self):
"""
Generates XML sample from YASD.
:return: XML element
:rtype: bs4.element.Tag
"""
self.xml = YASDXML(self.yaml, self.msgr).xml
return self.__output(self.xml, extname=".xml")
def document(self):
"""
Generates RST documentation.
:return: RST document
:rtype: str
"""
self.rst = YASDRST(self.yaml, self.msgr).rst
return self.__output(self.rst, extname=".rst")
def __output(self, outdata, extname=".xsd"):
"""
Prints in the terminal or writes into a file.
:return: Output data; str if outdata comes from YASDRST; otherwise
bs4.element.Tag
:rtype: str or bs4.element.Tag
"""
if self.stdout:
if type(outdata) is not str:
outdata = outdata.prettify(formatter=self.formatter)
if self.outfile is None:
print(outdata)
else:
suffix = self.outfile.suffix
if len(suffix) > 0 and suffix == suffix.replace(" ", ""):
extname = suffix
filename = f"{self.outfile.stem}{extname}"
filename = Path(self.outfile.parent / filename)
filename.write_text(outdata)
return outdata
class YASDXSD:
"""
YASD convertor to XSD.
"""
# TODO refactor so it fits XSD grammar, cfr. reference:
# https://www.w3schools.com/xml/schema_elements_ref.asp
def __init__(self, yml=None, messenger=None):
"""
Inits YASD convertor.
"""
self.msgr = YASDCheck.messenger(messenger)
self.yaml = YASDCheck.yaml(yml, self.msgr)
self.xsd = BeautifulSoup(parser="xml")
self.__build_schema()
self.__build_elements()
self.__build_attributes()
self.__build_groups()
self.__stringify_xsd()
if stdout:
self.__output()
else:
return self.out
def sample(self, stdout=False):
"""
Generates XML sample from YASD.
:param stdout: if sample goes to stdout or not; 'False' by default
:type stdout: True or False
"""
# TODO XML sample
self.out = "XML sample"
if stdout:
self.__output()
else:
return self.out
def document(self, stdout=False):
"""
Generates RST documentation.
:param stdout: if document goes to stdout or not; 'False' by default
:type stdout: True or False
"""
# TODO RST document
self.out = f"RST document from :{self.__dict__}"
if stdout:
self.__output()
else:
return self.out
def __build_schema(self):
"""
@ -112,7 +156,6 @@ class YASD:
"""
for key in ["version", "schemaLocation"]:
del self.yaml["schema"][key]
self.xsd = BeautifulSoup(parser="xml")
schema = self.xsd.new_tag("schema", nsprefix="xs")
schema["xmlns:xs"] = "http://www.w3.org/2001/XMLSchema"
for key, val in self.yaml["schema"].items():
@ -152,8 +195,6 @@ class YASD:
:param dict el: YASD element
:param str tag: tag name for XSD node
"""
# TODO fix according to 'attribute', 'element' and 'simpleType' refs
# https://www.w3schools.com/xml/schema_elements_ref.asp
element = self.xsd.new_tag(tag, nsprefix="xs")
if "default" in el.keys() and "fixed" in el.keys():
del el["fixed"]
@ -172,8 +213,6 @@ class YASD:
:param dict el: YASD element
"""
# TODO fix according to 'element' and 'complexType' refs
# https://www.w3schools.com/xml/schema_elements_ref.asp
element = self.__build_complex_root(el)
complex_type = self.__build_complex_type(el)
self.__add_references(complex_type, el, is_attr=True)
@ -313,32 +352,86 @@ class YASD:
del el["description"]
return el
def __stringify_xsd(self):
"""
Converts BeautifulSoups to pretty text format.
"""
self.out = self.xsd.prettify(formatter=self.formatter)
def __output(self, extname=".xsd"):
class YASDXML:
"""
YASD sampler to XML.
"""
# TODO XML Sample
def __init__(self, yml=None, messenger=None):
"""
Prints in the terminal or writes into a file.
Inits YASD sampler.
"""
if self.outfile is None:
print(self.out)
else:
suffix = self.outfile.suffix
if len(suffix) > 0 and suffix == suffix.replace(" ", ""):
extname = suffix
filename = f"{self.outfile.stem}{extname}"
filename = Path(self.outfile.parent / filename)
filename.write_text(self.out)
self.msgr = YASDCheck.messenger(messenger)
self.yaml = YASDCheck.yaml(yml, self.msgr)
self.xml = "XML sample"
class YASDRST:
"""
YASD document generator to RST.
"""
# TODO RST document
def __init__(self, yml=None, messenger=None):
"""
Inits YASD document generator.
"""
self.msgr = YASDCheck.messenger(messenger)
self.yaml = YASDCheck.yaml(yml, self.msgr)
self.rst = "RST document"
class YASDCheck:
"""
YASD input validator.
YASD validator.
Validates everything related to YASD classes.
"""
def messenger(msgr=None):
"""
Verifies if messenger was initialize.
:param messenger: Messenger object
:type messenger: None or YASDMessenger
"""
if msgr is None:
return YASDMessenger()
else:
return msgr
def yaml(yml=None, msgr=None):
"""
Verifies if yaml exists.
:param dict yml: YAML object
:param msgr: Messenger object
:type msgr: None or YASDMessenger
"""
msgr = YASDCheck.messenger(msgr)
if yml is None or type(yml) is not dict:
msgr.run("no_yaml", level="error")
else:
return yml
def file(filepath=None, msgr=None):
"""
Verififes if file exists.
:param filepath: File path
:type filepath: None or Path
"""
msgr = YASDCheck.messenger(msgr)
if type(filepath).__module__ != "pathlib":
msgr.run("no_input", level="error")
elif not filepath.exists() or not filepath.is_file():
msgr.run("invalid_input", level="error", file=filepath)
return filepath.resolve()
def __init__(self, indata=None, messenger=None):
"""
Inits YASD validator.
@ -348,29 +441,13 @@ class YASDCheck:
:param messenger: Object for print or save messages
:type messenger: None or YASDMessenger
"""
if messenger is None:
self.msgr = YASDMessenger()
else:
self.msgr = messenger
self.msgr = YASDCheck.messenger(messenger)
if type(indata) is dict:
self.yaml = indata
else:
self.yaml = self.parse_file(self.check_file(indata))
self.yaml = self.parse_file(YASDCheck.file(indata, self.msgr))
self.check_structure()
def check_file(self, filepath):
"""
Verifies YASD file.
:param filepath: YASD file path
:type filepath: None or Path
"""
if type(filepath).__module__ != "pathlib":
self.msgr.run("no_input", level="error")
elif not filepath.exists() or not filepath.is_file():
self.msgr.run("invalid_input", level="error", file=filepath)
return filepath.resolve()
def parse_file(self, filepath):
"""
Attempts YASD file parsing.
@ -429,6 +506,7 @@ class YASDMessenger:
"invalid_level": "Invalid log level '@lvl'",
"invalid_input": "Invalid file '@file'",
"invalid_yaml": "Invalid YAML structure",
"no_yaml": "YAML dict needed",
"no_input": "Input file needed.",
}
@ -501,7 +579,14 @@ class YASDCLI:
# TODO print man from README
print("Manual")
else:
YASD.do(args.action, args.input, args.output, args.quiet, args.log)
YASD.do(
args.action,
args.input,
args.output,
args.quiet,
args.log,
True,
)
def __init_parser(self):
"""