8000 Make BaseFormat more robust by mhxion · Pull Request #138 · uhd-urz/elAPI · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Make BaseFormat more robust #138

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 26, 2024
Merged

Make BaseFormat more robust #138

merged 8 commits into from
Aug 26, 2024

Conversation

mhxion
Copy link
Member
@mhxion mhxion commented Aug 25, 2024

BaseFormat only registers formatter classes in a 1D dictionary. Although, the 1D dictionary serves its purpose by letting built-in formatter classes (JSONFormat, YAMLFormat, CSVFormat) use/modify it, but once a plugin uses the BaseFormat dictionary as well by defining its own formatter classes, and once the plugin is loaded at elAPI runtime, the dictionary is inadvertently modified by the plugin, and is modified for all for good. Because of this reason, we couldn't use BaseFormat.supported_formatter_names for CLI documentation in doc.py, and used hard-coded strings instead.

With this PR, BaseFormat will register formatter classes in a 2D dictionary that is package-aware. We introduce package_identifier attribute to BaseFormat and __PACKAGE_IDENTIFIER__ for src/styles sub-package.

Internal plugins and third-party plugins should define their own formatter classes under a package/sub-package so Python magic method __package__* is not None or an empty string, and it can be passed to package_identifier.

# plugin_a/formats.py
# __init__.py exists in plugin_a. I.e., plugin_a is a package/sub-package
from elapi.styles import BaseFormat

class NEWFormat(BaseFormat):
    name: str = "new"
    convention: list[str] = name
    package_identifier: str = __package__  # __package__ should be "plugin_a"

    @classmethod
    def pattern(cls) -> str:
        return r"^new$"

    def __call__(self, data: Any) -> str:
        ...
  • BaseFormat will use package_identifier as a key in _registry so NEWFormat can be stored in a sub-dictionary of package_identifier.
  • BaseFormat will populate package_identifier first with built-in formatter classes.
  • BaseFormat will override an existing formatter class found in the package_identifier sub-dictionary if the new formatter class's pattern matches.
  • An existing formatter class can be disabled by assigning None to name attribute. As a precaution, assigning elapi.styles.__PACKAGE_IDENTIFIER__ to package_identifier while name == None will throw ValueError so as to not let the developers remove built-in formatter classes. E.g.:
# How CSVFormat is disabled in bill-teams
from elapi.styles import BaseFormat, CSVFormat as _CSVFormat

class DisabledCSVFormat(_CSVFormat, BaseFormat):
    name = None  # disables CSVFormat for package "__package__"
    package_identifier = __package__

    def __call__(self, data: Any):
        raise NotImplementedError

It should be clear by now, to access the registered formatter classes, Format (along with Highlight), newly renamed RegisterFormattingLanguage and CLIFormat must also be passed the package_identifier. E.g.:

format = CLIFormat(data_format, __package__, export_file_ext)

When a formatter class is not part a package, package_identifier can be spoofed and made to work out the following way:

# plugin_a/formats.py
# __init__.py does not exist in plugin_a. I.e., plugin_a is run as a script/top-level module
from elapi.styles import BaseFormat

class NEWFormat(BaseFormat):
    name: str = "new"
    convention: list[str] = name
    package_identifier: str = __package__ or PLUGIN_NAME  
    # If PLUGIN_NAME is not defined, it can be substituted with any static constant so long as it is used with all formatter classes as the `package_identifier`.

Other changes

uhd-urz optional dependencies (tenacity, python-dateutil) are bumped to latest versions.

References

*: https://stackoverflow.com/a/48833828

To remain consistent with this naming everywhere.
@mhxion mhxion self-assigned this Aug 25, 2024
@mhxion mhxion added this to the Complete bill-teams plugin milestone Aug 25, 2024
mhxion added 7 commits August 26, 2024 02:48
- Update tenacity
- Update python-dateutil
- Add package_identifier to BaseFormat; add package_identifier to Format; add package_identifier to built-in formatters (JSONFormat, YAMLFormat, CSVFormat)
- Add package_identifier keyword argument to supported_formatters and supported_formatter_names
- Rename ValidateLanguage to RegisterFormattingLanguage
- Add package_identifier support to RegisterFormattingLanguage; Throw KeyError if package_identifier is not registered before
- Add package_identifier to Highlight; add package_identifier to CLIFormat
- Add PDFAFormat and ZIPAFormat to plugins/experiments/formats ("experiments" plugin); add "reference" class attribute to them
- Use BaseFormat.supported_formatter_names in plugins/experiments/_doc.py instead of hard-coded strings
- Add DisabledCSVFormat to plugins/bill_teams/formats.py; Add package_identifier to JSONSortedFormat
- Remove remove_csv_formatter_support from plugins/bill_teams/formats.py
- Use BaseFormat.supported_formatter_names in plugins/bill_teams/_doc.py instead of hard-coded strings
- Use BaseFormat.supported_formatter_names in cli/doc.py instead of hard-coded strings
- Use __PACKAGE_IDENTIFIER__ as plugins_sub_package_identifier
- Replace "format.name.upper()" with "format.convention.upper()"
- Fix type annotation
@mhxion mhxion force-pushed the minor-improvements-2 branch from 9cb8c1c to b37f169 Compare August 26, 2024 00:49
@mhxion mhxion merged commit a1c9cdf into dev Aug 26, 2024
@mhxion mhxion deleted the minor-improvements-2 branch September 4, 2024 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant
0