Module metametameta.general
Utilities for generating source code metadata from existing metadata files.
Expand source code
"""
Utilities for generating source code metadata from existing metadata files.
"""
import re
from typing import Optional, Union
def any_metadict(metadata: dict[str, Union[str, int, float, list[str]]])->tuple[str, list[str]]:
"""
Generate a __about__.py file from a metadata dictionary.
Args:
metadata (dict): Metadata dictionary.
Returns:
tuple: The content to write to the file and the names of the variables.
"""
lines = []
names = []
for key, value in metadata.items():
if key == "name":
# __name__ is a reserved name.
lines.append(f'__title__ = "{value}"')
names.append("__title__")
continue
if key == "authors" and isinstance(value, list) and isinstance(value[0], str):
if len(value) == 1:
scalar = value[0].strip("[]' ")
email_pattern = "<([^>]+@[^>]+)>"
match = re.search(email_pattern, scalar)
if match is not None:
email = match.groups()[0]
author = scalar.replace("<" + email + ">", "").strip()
lines.append(f'__author__ = "{author}"')
lines.append(f'__author_email__ = "{email}"')
names.append("__author__")
names.append("__author_email__")
else:
lines.append(f'__author__ = "{scalar}"')
names.append("__author__")
else:
lines.append(f'__credits__ = "{value}"')
names.append("__credits__")
elif key == "classifiers" and isinstance(value, list):
for trove in value:
if trove.startswith("Development Status"):
lines.append(f'__status__ = "{trove.split("::")[1].strip()}"')
names.append("__status__")
elif key == "keywords" and isinstance(value, list):
lines.append(f"__keywords__ = {value}")
names.append("__keywords__")
# elif key in meta:
# content.append(f'__{key}__ = "{value}"')
else:
if not isinstance(value, (str, int, float)):
print("Skipping:", key, value)
continue
variable_name = key.lower().replace("-", "_")
quoted_value = safe_quote(value)
lines.append(f"__{variable_name}__ = {quoted_value}")
names.append(f"__{variable_name}__")
about_content = "\n".join(lines)
return about_content, names
def merge_sections(names: Optional[list[str]], project_name: str, about_content: str) -> str:
"""
Merge the sections of the __about__.py file.
Args:
names (list): Names of the variables.
project_name (str): Name of the project.
about_content (str): Content of the __about__.py file.
Returns:
str: Content of the __about__.py file.
"""
if names is None:
names = []
# Define the content to write to the __about__.py file
names = [f'\n "{item}"' for item in names]
all_header = "__all__ = [" + ",".join(names) + "\n]"
if project_name:
docstring = f"""\"\"\"Metadata for {project_name}.\"\"\"\n\n"""
else:
docstring = """\"\"\"Metadata.\"\"\"\n\n"""
return f"{docstring}{all_header}\n\n{about_content}"
def safe_quote(value: Union[int, float, str]) -> str:
"""
Safely quote a value.
Args:
value (Union[int,float,str]): Value to quote.
Returns:
str: Quoted value.
Examples:
>>> safe_quote('hello')
'"hello"'
>>> safe_quote('hello\\nworld')
'\"\"\"hello\\nworld\"\"\"'
"""
if not isinstance(value, (str,)):
return str(value)
if "\n" in value:
if '"""' in value:
value = value.replace('"""', '\\"\\"\\"')
quoted_value = f'"""{value}"""'
else:
quoted_value = f'"{value}"'
return quoted_value
Functions
def any_metadict(metadata: dict[str, typing.Union[str, int, float, list[str]]]) ‑> tuple[str, list[str]]
-
Generate a about.py file from a metadata dictionary.
Args
metadata
:dict
- Metadata dictionary.
Returns
tuple
- The content to write to the file and the names of the variables.
Expand source code
def any_metadict(metadata: dict[str, Union[str, int, float, list[str]]])->tuple[str, list[str]]: """ Generate a __about__.py file from a metadata dictionary. Args: metadata (dict): Metadata dictionary. Returns: tuple: The content to write to the file and the names of the variables. """ lines = [] names = [] for key, value in metadata.items(): if key == "name": # __name__ is a reserved name. lines.append(f'__title__ = "{value}"') names.append("__title__") continue if key == "authors" and isinstance(value, list) and isinstance(value[0], str): if len(value) == 1: scalar = value[0].strip("[]' ") email_pattern = "<([^>]+@[^>]+)>" match = re.search(email_pattern, scalar) if match is not None: email = match.groups()[0] author = scalar.replace("<" + email + ">", "").strip() lines.append(f'__author__ = "{author}"') lines.append(f'__author_email__ = "{email}"') names.append("__author__") names.append("__author_email__") else: lines.append(f'__author__ = "{scalar}"') names.append("__author__") else: lines.append(f'__credits__ = "{value}"') names.append("__credits__") elif key == "classifiers" and isinstance(value, list): for trove in value: if trove.startswith("Development Status"): lines.append(f'__status__ = "{trove.split("::")[1].strip()}"') names.append("__status__") elif key == "keywords" and isinstance(value, list): lines.append(f"__keywords__ = {value}") names.append("__keywords__") # elif key in meta: # content.append(f'__{key}__ = "{value}"') else: if not isinstance(value, (str, int, float)): print("Skipping:", key, value) continue variable_name = key.lower().replace("-", "_") quoted_value = safe_quote(value) lines.append(f"__{variable_name}__ = {quoted_value}") names.append(f"__{variable_name}__") about_content = "\n".join(lines) return about_content, names
def merge_sections(names: Optional[list[str]], project_name: str, about_content: str) ‑> str
-
Merge the sections of the about.py file.
Args
names
:list
- Names of the variables.
project_name
:str
- Name of the project.
about_content
:str
- Content of the about.py file.
Returns
str
- Content of the about.py file.
Expand source code
def merge_sections(names: Optional[list[str]], project_name: str, about_content: str) -> str: """ Merge the sections of the __about__.py file. Args: names (list): Names of the variables. project_name (str): Name of the project. about_content (str): Content of the __about__.py file. Returns: str: Content of the __about__.py file. """ if names is None: names = [] # Define the content to write to the __about__.py file names = [f'\n "{item}"' for item in names] all_header = "__all__ = [" + ",".join(names) + "\n]" if project_name: docstring = f"""\"\"\"Metadata for {project_name}.\"\"\"\n\n""" else: docstring = """\"\"\"Metadata.\"\"\"\n\n""" return f"{docstring}{all_header}\n\n{about_content}"
def safe_quote(value: Union[int, float, str]) ‑> str
-
Safely quote a value.
Args
value
:Union[int,float,str]
- Value to quote.
Returns
str
- Quoted value.
Examples
>>> safe_quote('hello') '"hello"' >>> safe_quote('hello\nworld') '"""hello\nworld"""'
Expand source code
def safe_quote(value: Union[int, float, str]) -> str: """ Safely quote a value. Args: value (Union[int,float,str]): Value to quote. Returns: str: Quoted value. Examples: >>> safe_quote('hello') '"hello"' >>> safe_quote('hello\\nworld') '\"\"\"hello\\nworld\"\"\"' """ if not isinstance(value, (str,)): return str(value) if "\n" in value: if '"""' in value: value = value.replace('"""', '\\"\\"\\"') quoted_value = f'"""{value}"""' else: quoted_value = f'"{value}"' return quoted_value