python/moz/l10n/resource/parse_resource.py (61 lines of code) (raw):
# Copyright Mozilla Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
from typing import Callable, cast
from ..formats import Format, UnsupportedFormat, detect_format
from ..formats.dtd.parse import dtd_parse
from ..formats.fluent.parse import fluent_parse
from ..formats.inc.parse import inc_parse
from ..formats.ini.parse import ini_parse
from ..formats.plain_json.parse import plain_json_parse
from ..formats.po.parse import po_parse
from ..formats.properties.parse import properties_parse
from ..formats.webext.parse import webext_parse
from ..model import Message, Resource
android_parse: Callable[..., Resource[Message]] | None
xliff_parse: Callable[[str | bytes], Resource[Message]] | None
try:
from ..formats.android.parse import android_parse
from ..formats.xliff.parse import xliff_parse
except ImportError:
android_parse = None
xliff_parse = None
def parse_resource(
input: Format | str | None,
source: str | bytes | None = None,
*,
android_ascii_spaces: bool = False,
android_literal_quotes: bool = False,
) -> Resource[Message]:
"""
Parse a Resource from its string representation.
The first argument may be an explicit Format,
the file path as a string, or None.
For the latter two types,
an attempt is made to detect the appropriate format.
If the first argument is a string path,
the `source` argument is optional,
as the file will be opened and read.
"""
input_is_file = False
if source is None:
if not isinstance(input, str):
raise TypeError("Source is required if type is not a string path")
with open(input, mode="rb") as file:
source = file.read()
input_is_file = True
# TODO post-py38: should be a match
format = input if isinstance(input, Format) else detect_format(input, source)
if format == Format.dtd:
return dtd_parse(source)
elif format == Format.fluent:
return fluent_parse(source)
elif format == Format.inc:
return inc_parse(source)
elif format == Format.ini:
return ini_parse(source)
elif format == Format.plain_json:
return plain_json_parse(source)
elif format == Format.po:
# Workaround for https://github.com/izimobil/polib/issues/170
return po_parse(cast(str, input) if input_is_file else source)
elif format == Format.properties:
return properties_parse(source)
elif format == Format.webext:
return webext_parse(source)
elif format == Format.android and android_parse is not None:
return android_parse(
source,
ascii_spaces=android_ascii_spaces,
literal_quotes=android_literal_quotes,
)
elif format == Format.xliff and xliff_parse is not None:
return xliff_parse(source)
else:
raise UnsupportedFormat(f"Unsupported resource format: {input}")