Skip to content
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

Update the set-keyword-status script #227

Merged
merged 3 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions scripts/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,16 @@ the heading with the keyword name.

## Changing the status of a keyword in Appendix A

To change the status color of a keyword in the status column in the alphabetical listing of keywords
in Appendix A, run for example:
To change the status of a keyword in the status column in the alphabetical listing
of keywords in Appendix A, run for example:

```
$ fodt-set-ketword-status --keyword=CSKIN --color=green
$ fodt-set-ketword-status --keyword=CSKIN --color=green --opm-flow
lisajulia marked this conversation as resolved.
Show resolved Hide resolved
```

this will change the color from orange to green.
this will change the color from orange to green and add the text "OPM Flow" to indicate
that the keyword is specific to OPM flow. If the keyword is not specific to OPM flow,
just omit the `--opm-flow` flag.

## Submitting a PR for a change to a `.fodt` file

Expand Down
86 changes: 66 additions & 20 deletions scripts/python/src/fodt/add_keyword_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,41 @@
from fodt.constants import ClickOptions, Directories, FileExtensions, KeywordStatus
from fodt.xml_helpers import XMLHelper

class AppendixStatusColorHandler(xml.sax.handler.ContentHandler):
def __init__(self, keyword: str, status: KeywordStatus) -> None:
class AppendixKeywordHandler(xml.sax.handler.ContentHandler):
def __init__(self, keyword: str, status: KeywordStatus, opm_flow: bool) -> None:
self.keyword = keyword
self.status = status
self.opm_flow = opm_flow
self.in_section = False
self.in_table_row = False
self.in_table_cell = False
self.in_table_cell_p = False
self.current_tag_name = None
self.content = io.StringIO()
self.current_keyword = None
self.keyword_found = False
self.keyword_handled = False
self.found_table_cell = False
self.office_body_found = False
self.in_table_cell_style = False
self.orange_styles = set()
self.green_styles = set()
self.start_tag_open = False # For empty tags, do not close with />

def characters(self, content: str):
if self.start_tag_open:
# NOTE: characters() is only called if there is content between the start
# tag and the end tag. If there is no content, characters() is not called.
self.content.write(">")
self.start_tag_open = False
if self.in_table_cell_p:
if self.opm_flow:
content = "OPM Flow"
else:
content = ""
self.keyword_handled = True
self.current_keyword = None
self.in_table_cell_p = False
self.found_table_cell = False
self.content.write(XMLHelper.escape(content))

def collect_table_cell_styles(self, attrs: xml.sax.xmlreader.AttributesImpl) -> None:
Expand All @@ -58,14 +76,27 @@ def collect_table_cell_styles(self, attrs: xml.sax.xmlreader.AttributesImpl) ->


def endElement(self, name: str):
if not self.keyword_found:
if not self.keyword_handled:
if name == "table:table-row":
self.in_table_row = False
elif self.in_table_row and name == "table:table-cell":
self.in_table_cell = False
elif self.in_table_cell_style and name == "style:style":
self.in_table_cell_style = False
self.content.write(XMLHelper.endtag(name))
if self.in_table_cell_p and name == "text:p" and self.start_tag_open and self.opm_flow:
self.content.write(">")
self.start_tag_open = False
content = "OPM Flow"
self.keyword_handled = True
self.current_keyword = None
self.in_table_cell_p = False
self.found_table_cell = False
self.content.write(XMLHelper.escape(content))
if self.start_tag_open:
self.content.write("/>")
self.start_tag_open = False
else:
self.content.write(XMLHelper.endtag(name))

def get_content(self) -> str:
return self.content.getvalue()
Expand All @@ -81,6 +112,7 @@ def handle_table_row(
self.in_table_row = True
self.current_keyword = None
elif self.in_table_row and name == 'table:table-cell':
self.in_table_cell = True
if (self.current_keyword is not None) and self.current_keyword == self.keyword:
logging.info(f"Found keyword {self.keyword}.")
# We have already found the keyword name within this table row
Expand All @@ -93,18 +125,19 @@ def handle_table_row(
else:
raise ValueError(f"Invalid status value: {self.status}.")
logging.info(f"Successfully changed status of keyword {self.keyword}.")
self.current_keyword = None
self.in_table_cell = False
self.keyword_found = True
else:
self.in_table_cell = True
self.found_table_cell = True
elif self.in_table_cell and name == 'text:a':
if "xlink:href" in attrs.getNames():
href = attrs.getValue("xlink:href")
# the href value is on the form "#1.2.1.ACTDIMS – ACTION Keyword Dimensions"
# we want to extract the keyword name from this string
if match := re.match(r"#\d+.\d+.\d+.(\w+)\s+", href):
self.current_keyword = match.group(1)
elif self.in_table_cell and name == 'text:p':
if self.found_table_cell:
logging.info(f"Found text:p element for keyword {self.keyword}.")
# replace the content of the text:p element with the new status
self.in_table_cell_p = True
return attrs

def select_table_cell_styles(self) -> None:
Expand All @@ -128,7 +161,10 @@ def startDocument(self):
self.content.write(XMLHelper.header)

def startElement(self, name:str, attrs: xml.sax.xmlreader.AttributesImpl):
if not self.keyword_found:
if self.start_tag_open:
self.content.write(">") # Close the start tag
self.start_tag_open = False
if not self.keyword_handled:
if not self.office_body_found:
if name == 'style:style':
if "style:family" in attrs.getNames():
Expand All @@ -143,25 +179,29 @@ def startElement(self, name:str, attrs: xml.sax.xmlreader.AttributesImpl):
self.office_body_found = True
else:
attrs = self.handle_table_row(name, attrs)
self.content.write(XMLHelper.starttag(name, attrs))
self.start_tag_open = True
self.content.write(XMLHelper.starttag(name, attrs, close_tag=False))


class UpdateKeywordStatus:
def __init__(self, maindir: str, keyword: str, status: KeywordStatus) -> None:
def __init__(
self, maindir: str, keyword: str, status: KeywordStatus, opm_flow: bool
) -> None:
self.keyword = keyword
self.status = status
self.maindir = maindir
self.opm_flow = opm_flow

def update(self) -> None:
self.filename = Path(self.maindir) / Directories.appendices / f"A.{FileExtensions.fodt}"
if not self.filename.is_file():
raise FileNotFoundError(f"File {self.filename} not found.")
# parse the xml file
parser = xml.sax.make_parser()
handler = AppendixStatusColorHandler(self.keyword, self.status)
handler = AppendixKeywordHandler(self.keyword, self.status, self.opm_flow)
parser.setContentHandler(handler)
parser.parse(self.filename)
if handler.keyword_found:
if handler.keyword_handled:
# Take a backup of the file
tempfile_ = tempfile.mktemp()
shutil.copy(self.filename, tempfile_)
Expand All @@ -176,16 +216,22 @@ def update(self) -> None:
@click.command()
@ClickOptions.maindir(required=False)
@click.option("--keyword", type=str, required=True, help="Keyword to change status for.")
@click.option("--status", type=str, required=True, help="New status for keyword.")
def set_keyword_status(maindir: str, keyword: str, status: str) -> None:
@click.option("--color", type=str, required=True, help="New status color for keyword.")
@click.option("--opm-flow", type=bool, default=False, is_flag=True, help="Flow specific keyword")
def set_keyword_status(
maindir: str,
keyword: str,
color: str,
opm_flow: bool
) -> None:
"""Change the status of a keyword in Appendix A."""
logging.basicConfig(level=logging.INFO)
try:
status = KeywordStatus[status.upper()]
color = KeywordStatus[color.upper()]
except ValueError:
raise ValueError(f"Invalid status value: {status}.")
logging.info(f"Setting status of keyword {keyword} to {status}.")
UpdateKeywordStatus(maindir, keyword, status).update()
logging.info(f"Updating parameters for keyword {keyword}: Color: {color}, flow-specific keyword: {opm_flow}.")
UpdateKeywordStatus(maindir, keyword, color, opm_flow).update()

if "__name__" == "__main__":
set_keyword_status()
Loading