Init
This commit is contained in:
commit
0afeca617b
|
@ -0,0 +1,411 @@
|
|||
---
|
||||
warn: This is just a prototype.
|
||||
---
|
||||
|
||||
# YASD, Yet Another Schema Definition
|
||||
|
||||
YASD is a YAML format for human writable XSDs (XML Schema Definition), humans
|
||||
declare what is indispensable, leaving the machines to do the rest of the
|
||||
unreadable `<syntaxis who_can_read_this="?" />`.
|
||||
|
||||
## Structure
|
||||
|
||||
General structure:
|
||||
|
||||
schema:
|
||||
SCHM
|
||||
elements:
|
||||
- ELMT
|
||||
...
|
||||
attributes:
|
||||
- ATTR
|
||||
...
|
||||
groups:
|
||||
- GRPS
|
||||
|
||||
Schema (SCHM) structure:
|
||||
|
||||
elementFormDefault: qualified|unqualified
|
||||
targetNamespace: http://a.link
|
||||
xmlns: http://a.link
|
||||
schemaLocation: http://a-link-to.xsd
|
||||
version: 0.1
|
||||
|
||||
Element (ELMT) structure:
|
||||
|
||||
name: element_name
|
||||
description: Element description
|
||||
type: simple|empty|no_text|no_elements|mixed
|
||||
datatype: string|integer|decimal|date|time|language|duration|token|boolean|byte|int|double|float|long|short|normalizedString|dateTime|gDay|gMonth|gMonthDay|gYear|gYearMonth|negativeInteger|nonNegativeInteger|nonPositiveInteger|positiveInteger|unsignedLong|unsignedInt|unsignedShort|unsignedByte|anyURI|base64Binary|hexBinary|Name|QName|NCName|ID|IDREF|IDREFS|ENTITY|ENTITIES|NMTOKEN|NMTOKENS|NOTATION
|
||||
default: a_value
|
||||
fixed: a_value
|
||||
restriction:
|
||||
CONSTRAIN
|
||||
...
|
||||
attribute:
|
||||
- attribute_name
|
||||
...
|
||||
children_order: all|choice|sequence
|
||||
children:
|
||||
- name: element_name
|
||||
maxOccurs: INTEGER
|
||||
minOccurs: INTEGER
|
||||
- group: group_name
|
||||
...
|
||||
|
||||
Attribute (ATTR) structure:
|
||||
|
||||
name: attribute_name
|
||||
description: Attribute description
|
||||
datatype: string|integer|decimal|date|time|language|duration|token|boolean|byte|int|double|float|long|short|normalizedString|dateTime|gDay|gMonth|gMonthDay|gYear|gYearMonth|negativeInteger|nonNegativeInteger|nonPositiveInteger|positiveInteger|unsignedLong|unsignedInt|unsignedShort|unsignedByte|anyURI|base64Binary|hexBinary|Name|QName|NCName|ID|IDREF|IDREFS|ENTITY|ENTITIES|NMTOKEN|NMTOKENS|NOTATION
|
||||
default: a_value
|
||||
fixed: a_value
|
||||
use: required
|
||||
restriction:
|
||||
CONSTRAIN
|
||||
...
|
||||
|
||||
Group (GRPS) structure:
|
||||
|
||||
name: group_name
|
||||
attribute_group: true|false
|
||||
children_order: all|choice|sequence
|
||||
children:
|
||||
- name: element_name
|
||||
maxOccurs: INTEGER|unbounded
|
||||
minOccurs: INTEGER
|
||||
|
||||
## Reference
|
||||
|
||||
### `elementFormDefault`[^1]
|
||||
|
||||
Indicates that any elements used by the XML instance document which were
|
||||
declared in this schema must be namespace qualified.
|
||||
|
||||
Optional; if not present by default is `unqualified`.
|
||||
|
||||
### `taget_namespace`[^1]
|
||||
|
||||
Indicates that the elements defined by this schema come from the specified URL
|
||||
namespace.
|
||||
|
||||
Optional.
|
||||
|
||||
### `xmlns`[^1]
|
||||
|
||||
Indicates that the default namespace is the specified URL.
|
||||
|
||||
Mandatory.
|
||||
|
||||
### `schemaLocation`[^1]
|
||||
|
||||
Indicates the location of the XML schema to use for that namespace.
|
||||
|
||||
Optional.
|
||||
|
||||
### `version`
|
||||
|
||||
Indicates XML schema version.
|
||||
|
||||
Mandatory.
|
||||
|
||||
### `name`
|
||||
|
||||
Indicates element or attribute name.
|
||||
|
||||
Mandatory.
|
||||
|
||||
For elements, its name is commonly known as tag name.
|
||||
|
||||
Naming rules:
|
||||
|
||||
- Element names are case-sensitive
|
||||
- Element names must start with a letter or underscore
|
||||
- Element names cannot start with the letters xml (or XML, or Xml, etc)
|
||||
- Element names can contain letters, digits, hyphens, underscores, and periods
|
||||
- Element names cannot contain spaces
|
||||
|
||||
### `description`
|
||||
|
||||
Indicates element or attribute description in human readable form.
|
||||
|
||||
Optional.
|
||||
|
||||
### `type`
|
||||
|
||||
Indicates element type.
|
||||
|
||||
Mandatory.
|
||||
|
||||
Allowed types:
|
||||
|
||||
- `simple`. Only text node allowed.
|
||||
- `empty`. Only attributes allowed.
|
||||
- `no_text`. No text nodes allowed.
|
||||
- `no_elements`. No children elements allowed.
|
||||
- `mixed`. Children elements, text node and attributes allowed.
|
||||
|
||||
Chart:
|
||||
|
||||
|type | children elements | text node | attributes |
|
||||
|------------|:-----------------:|:----------:|:----------:|
|
||||
|simple | ✗ | ✓ | ✗ |
|
||||
|empty | ✗ | ✗ | ✓ |
|
||||
|no_text | ✓ | ✗ | ✓ |
|
||||
|no_elements | ✗ | ✓ | ✓ |
|
||||
|mixed | ✓ | ✓ | ✓ |
|
||||
|
||||
> **Note**: attributes are never mandatory; they could be zero or more.
|
||||
|
||||
### `datatype`
|
||||
|
||||
Indicates element or attribute data types.[^2]
|
||||
|
||||
Only mandatory for 'simple' and 'no_elements' elements, and attributes.
|
||||
|
||||
Allowed String Data Types:
|
||||
|
||||
- `ENTITIES`.
|
||||
- `ENTITY`.
|
||||
- `ID`. A string that represents the ID attribute in XML (only used with
|
||||
schema attributes).
|
||||
- `IDREF`. A string that represents the IDREF attribute in XML (only used with
|
||||
schema attributes).
|
||||
- `IDREFS`.
|
||||
- `language`. A string that contains a valid language id.
|
||||
- `Name`. A string that contains a valid XML name.
|
||||
- `NCName`.
|
||||
- `NMTOKEN`. A string that represents the NMTOKEN attribute in XML (only used
|
||||
with schema attributes).
|
||||
- `NMTOKENS`.
|
||||
- `normalizedString`. A string that does not contain line feeds, carriage
|
||||
returns, or tabs.
|
||||
- `QName`.
|
||||
- `string`. A string.
|
||||
- `token`. A string that does not contain line feeds, carriage returns, tabs,
|
||||
leading or trailing spaces, or multiple spaces.
|
||||
|
||||
Allowed Date and Time Data Types:
|
||||
|
||||
- `date`. Defines a date value.
|
||||
- `dateTime`. Defines a date and time value.
|
||||
- `duration`. Defines a time interval.
|
||||
- `gDay`. Defines a part of a date - the day (DD).
|
||||
- `gMonth`. Defines a part of a date - the month (MM).
|
||||
- `gMonthDay`. Defines a part of a date - the month and day (MM-DD).
|
||||
- `gYear`. Defines a part of a date - the year (YYYY).
|
||||
- `gYearMonth`. Defines a part of a date - the year and month (YYYY-MM).
|
||||
- `time`. Defines a time value.
|
||||
|
||||
Allowed Numeric Data Types:
|
||||
|
||||
- `byte`. A signed 8-bit integer.
|
||||
- `decimal`. A decimal value.
|
||||
- `int`. A signed 32-bit integer.
|
||||
- `integer`. An integer value.
|
||||
- `long`. A signed 64-bit integer.
|
||||
- `negativeInteger`. An integer containing only negative values (..,-2,-1).
|
||||
- `nonNegativeInteger`. An integer containing only non-negative values
|
||||
(0,1,2,..).
|
||||
- `nonPositiveInteger`. An integer containing only non-positive values
|
||||
(..,-2,-1,0).
|
||||
- `positiveInteger`. An integer containing only positive values (1,2,..).
|
||||
- `short`. A signed 16-bit integer.
|
||||
- `unsignedLong`. An unsigned 64-bit integer.
|
||||
- `unsignedInt`. An unsigned 32-bit integer.
|
||||
- `unsignedShort`. An unsigned 16-bit integer.
|
||||
- `unsignedByte`. An unsigned 8-bit integer.
|
||||
|
||||
Allowed Miscellaneous Data Types:
|
||||
|
||||
- `anyURI`.
|
||||
- `base64Binary`.
|
||||
- `boolean`.
|
||||
- `double`.
|
||||
- `float`.
|
||||
- `hexBinary`.
|
||||
- `NOTATION`.
|
||||
- `QName`.
|
||||
|
||||
### `default`
|
||||
|
||||
Indicates default value when element or attribute is empty.
|
||||
|
||||
Optional.
|
||||
|
||||
### `fixed`
|
||||
|
||||
Indicates fixed value to element or attribute.
|
||||
|
||||
Optional.
|
||||
|
||||
### `use`
|
||||
|
||||
Indicates that the attribute is required.
|
||||
|
||||
Optional.
|
||||
|
||||
Only `required` is valid as value.
|
||||
|
||||
### `restriction`[^3]
|
||||
|
||||
Indicates accepted constrained values for element or attribute.
|
||||
|
||||
Optional; if present, must contain at least one constrain.
|
||||
|
||||
Not allowed for 'empty' and 'no_text' elements.
|
||||
|
||||
Allowed constrains:
|
||||
|
||||
- `enumeration`. Specifies a list of acceptable values.
|
||||
- `fractionDigits`. Specifies the maximum number of decimal places allowed;
|
||||
must be equal to or greater than zero.
|
||||
- `length`. Specifies the exact number of characters or list items allowed;
|
||||
must be equal to or greater than zero.
|
||||
- `maxExclusive`. Specifies the upper bounds for numeric values (the value
|
||||
must be less than this value).
|
||||
- `maxInclusive`. Specifies the upper bounds for numeric values (the value
|
||||
must be less than or equal to this value).
|
||||
- `maxLength`. Specifies the maximum number of characters or list items
|
||||
allowed; must be equal to or greater than zero.
|
||||
- `minExclusive`. Specifies the lower bounds for numeric values (the value
|
||||
must be greater than this value).
|
||||
- `minInclusive`. Specifies the lower bounds for numeric values (the value
|
||||
must be greater than or equal to this value).
|
||||
- `minLength`. Specifies the minimum number of characters or list items
|
||||
allowed; must be equal to or greater than zero.
|
||||
- `pattern`. Defines the exact sequence of characters that are acceptable.
|
||||
- `totalDigits`. Specifies the exact number of digits allowed; must be greater
|
||||
than zero.
|
||||
- `whiteSpace`. Specifies how white space (line feeds, tabs, spaces, and
|
||||
carriage returns) is handled; accepted values are
|
||||
`preserve|replace|collapse`.
|
||||
|
||||
### `attribute`
|
||||
|
||||
Indicates a list of attributes for an element.
|
||||
|
||||
### `children_order`
|
||||
|
||||
Indicates order indicators for children elements.
|
||||
|
||||
Mandatory in `no_text` or `mixed` elements, and group.
|
||||
|
||||
Allowed values:
|
||||
|
||||
- `all`. Children elements can occur in any order.
|
||||
- `choice`. Only one children element can accur.
|
||||
- `sequence`. Children elements must occur in specified order.
|
||||
|
||||
### `children`
|
||||
|
||||
Indicates a list of children elements.
|
||||
|
||||
Mandatory in `no_text` or `mixed` elements, and group.
|
||||
|
||||
### `maxOccurs`
|
||||
|
||||
Indicates max number of times a children element can accur.
|
||||
|
||||
Optional; if not present by default is `1`.
|
||||
|
||||
Valid values are non negative integer or `unbounded` for unlimited number of
|
||||
times.
|
||||
|
||||
### `minOccurs`
|
||||
|
||||
Indicates min number of times a children element can accur.
|
||||
|
||||
Optional; if not present by default is `1`.
|
||||
|
||||
Valid value is non negative integer.
|
||||
|
||||
### `group`
|
||||
|
||||
Indicates group name.
|
||||
|
||||
Optional.
|
||||
|
||||
### `groups`
|
||||
|
||||
Indicates element or attribute groups for schema.
|
||||
|
||||
Optional.
|
||||
|
||||
### `attribute_group`
|
||||
|
||||
Indicates if group is an attribute group.
|
||||
|
||||
Optional; if not present by default is `false`.
|
||||
|
||||
Allowed values:
|
||||
|
||||
- `true`.
|
||||
- `false`.
|
||||
|
||||
### `elements`
|
||||
|
||||
Indicates elements for schema.
|
||||
|
||||
Mandatory.
|
||||
|
||||
### `attributes`
|
||||
|
||||
Indicates attributes for schema.
|
||||
|
||||
Optional.
|
||||
|
||||
### `schema`
|
||||
|
||||
Indicates schema general information.
|
||||
|
||||
Mandatory.
|
||||
|
||||
## Command-Line Interface
|
||||
|
||||
```
|
||||
yasd [-q | -l] CMD
|
||||
|
||||
CMD (mandatory and only one at once):
|
||||
|
||||
convert [-f xsd | json] FILE
|
||||
check FILE
|
||||
sample [-n INT] FILE
|
||||
man
|
||||
help
|
||||
|
||||
ARGS:
|
||||
|
||||
-q | --quiet No prints; doesn't apply for man and help.
|
||||
-l | --logs Writes logs.
|
||||
-f | --format Format type; could be 'xsd' or 'json'; 'xsd' by default.
|
||||
-n | --num Number of samples; 1 by default.
|
||||
convert Converts YASD file to XSD or JSON format; XSD by default.
|
||||
check Validates YASD file.
|
||||
sample Writes XML samples according to schema.
|
||||
man Prints README.md
|
||||
help Prints this.
|
||||
FILE YAML file; file extension doesn't matter.
|
||||
|
||||
EXAMPLES:
|
||||
|
||||
yasd convert schema.yasd
|
||||
yasd --quiet --logs convert schema.yasd
|
||||
yasd -ql -f json convert schema.yasd
|
||||
yasd check schema.yaml
|
||||
yasd sample schema.yasd
|
||||
yasd sample -n 10 schema.yaml
|
||||
yasd man
|
||||
yasd help
|
||||
```
|
||||
|
||||
[^1]: The following explanation is practically a copy-paste from "XSD - The
|
||||
<schema> Element", W3Schools. Cfr.
|
||||
<https://www.w3schools.com/xml/schema_schema.asp>.
|
||||
|
||||
[^2]: The following explanation is practically a copy-paste from "XSD Data
|
||||
Types", W3Schools. Cfr. <https://www.w3schools.com/xml/schema_intro.asp>.
|
||||
|
||||
[^3]: The following explanation is practically a copy-paste from "XSD
|
||||
Restrictions/Facets", W3Schools. Cfr.
|
||||
<https://www.w3schools.com/xml/schema_facets.asp>.
|
|
@ -0,0 +1,348 @@
|
|||
#!/usr/bin/env python
|
||||
# (c) 2023 Perro Tuerto <hi@perrotuerto.blog>.
|
||||
# Founded by Mexican Academy of Language <https://academia.org.mx>.
|
||||
# Licensed under GPLv3 <https://www.gnu.org/licenses/gpl-3.0.en.html>.
|
||||
|
||||
import sys
|
||||
import yaml
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from bs4 import BeautifulSoup
|
||||
from bs4.formatter import XMLFormatter
|
||||
|
||||
|
||||
class YASD:
|
||||
"""
|
||||
Performs YASD actions.
|
||||
"""
|
||||
|
||||
def do(quiet, log, samples, action, filepath):
|
||||
yasd = YASD(quiet, log, samples, filepath)
|
||||
if action == "convert":
|
||||
yasd.convert()
|
||||
elif action == "sample":
|
||||
yasd.sample()
|
||||
elif action == "document":
|
||||
yasd.document()
|
||||
|
||||
def __init__(self, quiet=False, log=False, samples=1, filepath=None):
|
||||
"""
|
||||
Inits YASD object.
|
||||
|
||||
:param quiet: If messages are print or not; 'False' by default
|
||||
:type quiet: False or True
|
||||
:param log: If messages are write in a file or not; 'False' by default
|
||||
:type log: False or True
|
||||
:param int samples: Quantity of XML samples; '1' by default
|
||||
:param filepath: YASD file path; 'None' by default
|
||||
:type filepath: None or Path
|
||||
"""
|
||||
self.msgr = YASDMessenger(quiet=quiet, log=log)
|
||||
valid_input = YASDCheck(self.msgr, filepath)
|
||||
self.filepath = valid_input.filepath
|
||||
self.yaml = valid_input.yaml
|
||||
self.samples = samples
|
||||
self.soups = {
|
||||
"schema": "",
|
||||
"elements": "",
|
||||
"attributes": "",
|
||||
"groups": "",
|
||||
}
|
||||
|
||||
def convert(self):
|
||||
"""
|
||||
Converts YASD to XSD.
|
||||
"""
|
||||
self.__build_schema()
|
||||
self.__build_elements()
|
||||
self.__build_attributes()
|
||||
self.__write()
|
||||
|
||||
def sample(self):
|
||||
"""
|
||||
Generates XML samples from YASD.
|
||||
"""
|
||||
print(f"TODO: {self.samples} samples")
|
||||
|
||||
def document(self):
|
||||
"""
|
||||
Generates MD documentation
|
||||
"""
|
||||
print("TODO: MD document from :", self.__dict__)
|
||||
|
||||
def __build_schema(self):
|
||||
unwanted = "version schemaLocation".split()
|
||||
for key in unwanted:
|
||||
self.yaml["schema"].pop(key)
|
||||
soup = BeautifulSoup(parser="xml")
|
||||
schema = soup.new_tag("schema", nsprefix="xs")
|
||||
schema["xmlns:xs"] = "http://www.w3.org/2001/XMLSchema"
|
||||
soup.append(schema)
|
||||
for key, val in self.yaml["schema"].items():
|
||||
schema[key] = val
|
||||
self.soups["schema"] = soup
|
||||
|
||||
def __build_elements(self):
|
||||
soup = BeautifulSoup(parser="xml")
|
||||
for el in self.yaml["elements"]:
|
||||
el = self.__sanitize(el)
|
||||
{
|
||||
"simple": self.__build_element_simple(soup, el),
|
||||
"empty": self.__build_element_empty(soup, el),
|
||||
"no_text": self.__build_element_no_text(soup, el),
|
||||
"no_elements": self.__build_element_no_elements(soup, el),
|
||||
"mixed": self.__build_element_mixed(soup, el),
|
||||
}[el["type"]]
|
||||
if len(soup.contents) > 0:
|
||||
print(len(soup.contents))
|
||||
self.soups["elements"] = soup
|
||||
|
||||
def __build_element_simple(self, main_soup, el):
|
||||
# element = self.__build_simple(el)
|
||||
# main_soup.append(element)
|
||||
...
|
||||
|
||||
def __build_element_empty(self, main_soup, el):
|
||||
...
|
||||
|
||||
def __build_element_no_text(self, main_soup, el):
|
||||
...
|
||||
|
||||
def __build_element_no_elements(self, main_soup, el):
|
||||
...
|
||||
|
||||
def __build_element_mixed(self, main_soup, el):
|
||||
...
|
||||
|
||||
def __build_attributes(self):
|
||||
soup = BeautifulSoup(parser="xml")
|
||||
for el in self.yaml["attributes"]:
|
||||
element = self.__build_simple(self.__sanitize(el), tag="attribute")
|
||||
soup.append(element)
|
||||
self.soups["attributes"] = soup
|
||||
|
||||
def __build_simple(self, el, tag="element"):
|
||||
soup = BeautifulSoup(parser="xml")
|
||||
element = soup.new_tag(tag, nsprefix="xs")
|
||||
soup.append(element)
|
||||
for key, val in el.items():
|
||||
if key == "datatype":
|
||||
element["type"] = f"xs:{val}"
|
||||
elif key == "restriction":
|
||||
self.__build_restriction(element, val)
|
||||
else:
|
||||
element[key] = val
|
||||
return soup
|
||||
|
||||
def __build_restriction(self, root, elements):
|
||||
soup = BeautifulSoup(parser="xml")
|
||||
simple_type = soup.new_tag("simpleType", nsprefix="xs")
|
||||
restriction = soup.new_tag("restriction", nsprefix="xs")
|
||||
restriction["base"] = self.__get_base(list(elements.keys())[0])
|
||||
for key, val in elements.items():
|
||||
constrain = soup.new_tag(key, nsprefix="xs", value=val)
|
||||
restriction.append(constrain)
|
||||
simple_type.append(restriction)
|
||||
root.append(simple_type)
|
||||
|
||||
def __sanitize(self, el):
|
||||
"""
|
||||
Prepares element or attribute for conversion.
|
||||
|
||||
It eliminates 'description' key.
|
||||
|
||||
:param dict el: Element or attribute as a dictionary
|
||||
:return: Sanitized element or attribute
|
||||
:rtype: dict
|
||||
"""
|
||||
if "description" in el.keys():
|
||||
del el["description"]
|
||||
return el
|
||||
|
||||
def __get_base(self, key):
|
||||
"""
|
||||
Gets restriction data type.
|
||||
|
||||
:param str key: Type of restriction
|
||||
:return: 'xs:string' or 'xs:integer'
|
||||
:rtype: str
|
||||
"""
|
||||
strings = "enumeration pattern whiteSpace length minLength maxLength"
|
||||
if key in strings.split():
|
||||
return "xs:string"
|
||||
else:
|
||||
return "xs:integer"
|
||||
|
||||
def __write(self):
|
||||
"""
|
||||
Writes XSD into a file.
|
||||
"""
|
||||
filename = Path(self.filepath.parent / f"{self.filepath.stem}.xsd")
|
||||
formatter = XMLFormatter(indent=2)
|
||||
for key, val in self.soups.items():
|
||||
if key == "schema":
|
||||
xsd = val.schema
|
||||
else:
|
||||
xsd.append(val)
|
||||
filename.write_text(xsd.prettify(formatter=formatter))
|
||||
|
||||
|
||||
class YASDCheck:
|
||||
"""
|
||||
Verifies YASD file.
|
||||
"""
|
||||
|
||||
def __init__(self, messenger, filepath):
|
||||
"""
|
||||
Inits YASD validator.
|
||||
|
||||
:param YASDMessenger messenger: Object for print or save messages
|
||||
:param filepath: YASD file path
|
||||
:type filepath: None or Path
|
||||
"""
|
||||
self.msgr = messenger
|
||||
self.__check_file(filepath)
|
||||
self.__parse_file()
|
||||
# TODO: do extra checks
|
||||
|
||||
def __check_file(self, filepath):
|
||||
"""
|
||||
Verifies YASD file.
|
||||
|
||||
:param filepath: YASD file path
|
||||
:type filepath: None or Path
|
||||
"""
|
||||
if filepath is None:
|
||||
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)
|
||||
self.filepath = filepath.resolve()
|
||||
|
||||
def __parse_file(self):
|
||||
"""
|
||||
Attempts YASD file parsing.
|
||||
"""
|
||||
raw = self.filepath.read_text(encoding="utf8")
|
||||
try:
|
||||
self.yaml = yaml.safe_load(raw)
|
||||
except yaml.YAMLError:
|
||||
# TODO: should be log class
|
||||
self.msgr.run("invalid_yaml", level="error")
|
||||
|
||||
|
||||
class YASDMessenger:
|
||||
"""
|
||||
Prints or saves YASD messages.
|
||||
"""
|
||||
|
||||
def keys():
|
||||
"""
|
||||
Messages keys dictionary.
|
||||
"""
|
||||
return {
|
||||
"invalid_level": "Invalid log level '@lvl'",
|
||||
"no_input": "Input file needed.",
|
||||
"invalid_input": "Invalid file '@file'",
|
||||
"invalid_yaml": "Invalid YAML structure",
|
||||
}
|
||||
|
||||
def __init__(self, quiet=False, log=False):
|
||||
"""
|
||||
Inits YASD Messenger.
|
||||
"""
|
||||
self.quiet = quiet
|
||||
self.log = log
|
||||
|
||||
def run(self, key="", level="info", **kwargs):
|
||||
"""
|
||||
Prints or writes messages.
|
||||
|
||||
'**kwargs' are the keys for message text replacements.
|
||||
|
||||
:param str key: Message key
|
||||
:param str level: Log level; 'info' by default
|
||||
"""
|
||||
self.__check_level(level)
|
||||
msg = self.__get_msg(key, **kwargs)
|
||||
msg = f"[{level.upper()}] {msg}"
|
||||
# TODO: print or save depending on self.quiet and self.log
|
||||
print(msg)
|
||||
if level in ["error", "fatal"]:
|
||||
sys.exit(1)
|
||||
|
||||
def __check_level(self, level):
|
||||
"""
|
||||
Verifies log level.
|
||||
|
||||
Prints warning if log level doesn't exist.
|
||||
|
||||
:param str level: Log level
|
||||
"""
|
||||
if not level in ["trace", "debug", "info", "warn", "error", "fatal"]:
|
||||
YASDMessenger().run("invalid_level", level="warn", lvl=level)
|
||||
|
||||
def __get_msg(self, key, **kwargs):
|
||||
"""
|
||||
Gets message based on key.
|
||||
|
||||
'**kwargs' are the keys for message text replacements.
|
||||
|
||||
:param str key: Message key
|
||||
:return: Message or key if message key doesn't exist.
|
||||
:rtype: str
|
||||
"""
|
||||
if key in YASDMessenger.keys().keys():
|
||||
msg = YASDMessenger.keys()[key]
|
||||
for key, value in kwargs.items():
|
||||
msg = msg.replace(f"@{key}", str(value))
|
||||
return msg
|
||||
else:
|
||||
return key
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Gets and parses argv, then calls YASD.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="yasd",
|
||||
description="""
|
||||
YASD, Yet Another Schema Definition.
|
||||
YASD is a YAML format for human writable XSDs (XML Schema Definition),
|
||||
humans declare what is indispensable, leaving the machines to do the
|
||||
rest of the unreadable <syntaxis who_can_read_this="?" />.
|
||||
""",
|
||||
epilog="""
|
||||
(c) 2023 Perro Tuerto <hi@perrotuerto.blog>.
|
||||
Founded by Mexican Academy of Language <https://academia.org.mx>.
|
||||
Licensed under GPLv3 <https://www.gnu.org/licenses/gpl-3.0.en.html>.
|
||||
""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"action",
|
||||
choices=["convert", "check", "sample", "document", "man"],
|
||||
help="action to perform",
|
||||
)
|
||||
parser.add_argument(
|
||||
"file",
|
||||
type=Path,
|
||||
nargs="?",
|
||||
default=None,
|
||||
help="file in YAML format",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-q", "--quiet", action="store_true", help="enable quiet mode"
|
||||
)
|
||||
parser.add_argument("-l", "--log", action="store_true", help="write log")
|
||||
parser.add_argument(
|
||||
"-n", "--num", default=1, help="number of XML samples; 1 by default"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
if args.action == "man":
|
||||
print("MAN")
|
||||
else:
|
||||
YASD.do(args.quiet, args.log, args.num, args.action, args.file)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue