pytex/PyTeX/format/pytex_formatter.py

216 lines
8.8 KiB
Python
Raw Normal View History

2022-02-07 18:36:30 +01:00
import re
2022-02-06 15:10:28 +01:00
from pathlib import Path
from typing import Optional, Dict, TextIO
2022-02-07 18:36:30 +01:00
from .constants import *
2022-02-06 15:10:28 +01:00
from .formatterif import FormatterIF
from .formatting_config import FormattingConfig
from .git_version_info import GitVersionInfo
2022-02-06 15:10:28 +01:00
from .generic_text import GenericText
from ..logger import logger
from abc import ABC, abstractmethod
from .enums import *
from datetime import *
2022-02-08 17:04:16 +01:00
class PyTeXFormatter(FormatterIF, ABC):
2022-02-06 15:10:28 +01:00
def __init__(
self,
input_file: Optional[Path] = None,
config: Optional[FormattingConfig] = None,
git_version_info: Optional[GitVersionInfo] = None,
locate_file_config: bool = True,
allow_infile_config: bool = True
2022-02-06 15:10:28 +01:00
):
super().__init__(
input_file=input_file,
config=config
)
self._config: Optional[FormattingConfig] = self._config # for type-hinting
self._git_version_info: Optional[GitVersionInfo] = git_version_info
self._allow_infile_config: bool = allow_infile_config
2022-02-06 15:10:28 +01:00
self._header: Optional[GenericText] = None
if locate_file_config:
file_config = self.parse_file_config()
if allow_infile_config:
infile_config = self.parse_infile_config()
self._config = \
file_config.merge_with(
infile_config,
strict=True
2022-02-08 19:01:18 +01:00
).merge_with(self.config, strict=False)
else:
2022-02-08 19:01:18 +01:00
self._config = file_config.merge_with(self.config)
else:
if allow_infile_config:
infile_config = self.parse_infile_config()
2022-02-08 19:01:18 +01:00
self._config = infile_config.merge_with(self.config)
self._output_file: Optional[TextIO] = None # This may change over time in case of multiple output files
self._attribute_dict: Optional[Dict] = None
2022-02-08 16:34:59 +01:00
def parse_file_config(self) -> FormattingConfig:
config_file = self.input_file.with_name(self.input_file.name + PYTEX_CONFIG_FILE_EXTENSION)
if config_file.exists():
try:
2022-02-08 16:34:59 +01:00
return FormattingConfig.from_yaml(config_file)
except:
raise NotImplementedError # Invalid yaml file format
else:
2022-02-08 16:34:59 +01:00
return FormattingConfig()
2022-02-08 16:34:59 +01:00
def parse_infile_config(self) -> FormattingConfig:
if self._input_file is None:
raise NotImplementedError # no file initialised yet
with open(self._input_file, "r") as file:
line = file.readline()
if re.match(self.config.escape_character + INFILE_CONFIG_BEGIN_CONFIG, line):
if not line.strip().lstrip('%').strip() == self.config.escape_character + INFILE_CONFIG_BEGIN_CONFIG:
logger.warning(
"File {file}: Start of infile config invalid."
)
config = []
while True:
line = file.readline()
if re.match(self.config.escape_character + INFILE_CONFIG_END_CONFIG, line):
if not line.strip().lstrip(
'%').strip() == self.config.escape_character + INFILE_CONFIG_END_CONFIG:
logger.warning(
"File {file}: End of infile config invalid."
)
break
if line == '':
raise NotImplementedError # No matching end block
config.append(line.lstrip('%').rstrip())
try:
2022-02-08 16:34:59 +01:00
return FormattingConfig.from_yaml('\n'.join(config))
except:
raise NotImplementedError # Invalid yaml file format
else:
2022-02-08 16:34:59 +01:00
return FormattingConfig()
2022-02-06 15:10:28 +01:00
@property
def config(self) -> FormattingConfig:
if self._config is None:
2022-02-08 19:01:18 +01:00
return FormattingConfig()
2022-02-06 15:10:28 +01:00
return self._config
2022-02-08 16:34:59 +01:00
@config.setter
def config(self, formatting_config: FormattingConfig):
self._config = formatting_config
@property
def git_version_info(self) -> GitVersionInfo:
if self._git_version_info is None:
return GitVersionInfo()
else:
return self._git_version_info
2022-02-06 15:10:28 +01:00
@property
def header(self) -> GenericText:
if self._header is None:
if not (
self.config.include_extra_header
2022-02-08 16:34:59 +01:00
or self.config.include_time
or self.config.include_pytex_version
or self.config.include_pytex_info_text
or self.config.include_repo_version
or self.config.include_repo_info_text
2022-02-06 15:10:28 +01:00
):
2022-02-08 23:34:18 +01:00
self._header = GenericText()
else:
2022-02-08 23:34:18 +01:00
self._header = GenericText()
# TODO: handle license
if self.config.include_extra_header:
self._header += self.config.extra_header + ['']
if self.config.include_repo_info_text:
self._header += self.config.repo_info_text
if self.config.include_pytex_info_text:
self._header += self.config.pytex_info_text + ['']
## TODO handle rest
return self._header
2022-02-06 16:08:05 +01:00
def _update_attribute_dict(self):
self._attribute_dict: Dict[str, str] = {
FormatterProperty.author.value: self.config.author,
FormatterProperty.shortauthor.value: self.shortauthor,
FormatterProperty.date.value: datetime.now().strftime('%Y/%m/%d'),
FormatterProperty.year.value: datetime.now().strftime('%Y'),
FormatterProperty.raw_name.value: self.raw_name,
FormatterProperty.name.value: self.name,
FormatterProperty.version.value: self.config.version,
FormatterProperty.file_name.value: self.current_file_name,
FormatterProperty.source_file_name.value: self._input_file.name,
FormatterProperty.repo_version.value: self.git_version_info.repo_version.version,
FormatterProperty.repo_branch.value: self.git_version_info.repo_version.branch,
FormatterProperty.repo_commit.value: self.git_version_info.repo_version.commit_hash,
FormatterProperty.repo_dirty.value: self.git_version_info.repo_version.dirty,
FormatterProperty.pytex_version.value: self.git_version_info.pytex_version.version,
FormatterProperty.pytex_branch.value: self.git_version_info.pytex_version.branch,
FormatterProperty.pytex_commit.value: self.git_version_info.pytex_version.commit_hash,
FormatterProperty.pytex_dirty.value: self.git_version_info.pytex_version.dirty,
FormatterProperty.tex_type.value: self.config.tex_type.value,
FormatterProperty.tex_flavour.value: self.config.tex_flavour.value,
2022-02-09 19:50:49 +01:00
FormatterProperty.file_prefix.value: self.file_prefix,
2022-02-09 21:11:46 +01:00
FormatterProperty.description.value: self.config.description,
FormatterProperty.Tex_type.value: self.config.tex_type.value.capitalize()
}
@property
def attribute_dict(self) -> Dict:
if self._attribute_dict is None:
self._update_attribute_dict()
return self._attribute_dict
@property
def shortauthor(self) -> str:
2022-02-09 17:31:06 +01:00
parts = self.config.author.lower().replace('ß', 'ss').split(' ') # TODO: better non-alphanumeric handling
if len(parts) == 1:
return parts[0]
else:
return parts[0][0] + parts[-1]
@property
def raw_name(self) -> str:
2022-02-09 15:39:36 +01:00
parts = self._input_file.name.split('.', maxsplit=1)
if not len(parts) == 2:
raise NotImplementedError # invalid file name
else:
return parts[0]
@property
def file_prefix(self) -> str:
if self.config.naming_scheme == NamingScheme.prepend_author:
if self.config.tex_flavour == TeXFlavour.LaTeX2e:
return self.shortauthor + '@' + self.raw_name
elif self.config.tex_flavour == TeXFlavour.LaTeX3:
return self.shortauthor + '_' + self.raw_name
else:
raise NotImplementedError
else:
return self.raw_name
@property
def name(self):
if self.config.naming_scheme == NamingScheme.prepend_author:
return self.shortauthor + '-' + self.raw_name
else:
return self.raw_name
def current_file_name(self):
return self._output_file.name
2022-02-06 18:51:49 +01:00
def make_header(self, **kwargs) -> str:
try:
return '\n'.join(
[
'%' * 80,
self.header.format(**self.attribute_dict),
'%' * 80,
''
]
)
except KeyError:
raise NotImplementedError