[release_table] Support specifying a column by its index
Column could only be referenced by their name. Now they can also be referenced by their 1-based index.
This commit is contained in:
@@ -23,7 +23,7 @@ necessary information. Available configuration options are:
|
|||||||
- ignore_empty_releases (optional, default = false): A boolean value indicating whether to ignore releases with no
|
- ignore_empty_releases (optional, default = false): A boolean value indicating whether to ignore releases with no
|
||||||
fields except the name.
|
fields except the name.
|
||||||
- fields: A dictionary that maps release fields to the table's columns. Field definition include:
|
- fields: A dictionary that maps release fields to the table's columns. Field definition include:
|
||||||
- column (mandatory): The name of the column in the table. This is case-insensitive.
|
- column (mandatory): The name or index (starts at 1) of the column in the table.
|
||||||
- type (mandatory, default = string): The type of the field. Supported types are:
|
- type (mandatory, default = string): The type of the field. Supported types are:
|
||||||
- string: The raw string value.
|
- string: The raw string value.
|
||||||
- date : A full or year-month date (supported patterns available in common.dates).
|
- date : A full or year-month date (supported patterns available in common.dates).
|
||||||
@@ -38,6 +38,20 @@ necessary information. Available configuration options are:
|
|||||||
- template (mandatory, default = DEFAULT_TEMPLATE): A liquid template used to clean up the value using the matched
|
- template (mandatory, default = DEFAULT_TEMPLATE): A liquid template used to clean up the value using the matched
|
||||||
groups from a 'regex'.
|
groups from a 'regex'.
|
||||||
|
|
||||||
|
Note that defining the column attribute directly instead of its full definition is allowed when
|
||||||
|
there the column name or index is the only attribute. For example, this:
|
||||||
|
```
|
||||||
|
fields:
|
||||||
|
releaseCycle:
|
||||||
|
column: "End of life"
|
||||||
|
```
|
||||||
|
|
||||||
|
can be replaced with this:
|
||||||
|
```
|
||||||
|
fields:
|
||||||
|
releaseCycle: "End of life"
|
||||||
|
```
|
||||||
|
|
||||||
Supported CSS selectors are defined by BeautifulSoup and documented on its website. For more information, see
|
Supported CSS selectors are defined by BeautifulSoup and documented on its website. For more information, see
|
||||||
https://beautiful-soup-4.readthedocs.io/en/latest/index.html?highlight=selector#css-selectors."""
|
https://beautiful-soup-4.readthedocs.io/en/latest/index.html?highlight=selector#css-selectors."""
|
||||||
|
|
||||||
@@ -54,7 +68,9 @@ TODAY = dates.today()
|
|||||||
|
|
||||||
class Field:
|
class Field:
|
||||||
def __init__(self, name: str, definition: str | dict) -> None:
|
def __init__(self, name: str, definition: str | dict) -> None:
|
||||||
if isinstance(definition, str):
|
# Directly specifying the column name or index instead of its full definition is allowed.
|
||||||
|
# In this case we must convert it to a full definition.
|
||||||
|
if isinstance(definition, (str, int)):
|
||||||
definition = {"column": definition}
|
definition = {"column": definition}
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
@@ -63,7 +79,12 @@ class Field:
|
|||||||
definition["regex"] = definition.get("regex", [DEFAULT_RELEASE_REGEX])
|
definition["regex"] = definition.get("regex", [DEFAULT_RELEASE_REGEX])
|
||||||
definition["template"] = definition.get("template", DEFAULT_TEMPLATE)
|
definition["template"] = definition.get("template", DEFAULT_TEMPLATE)
|
||||||
|
|
||||||
self.column = definition["column"].lower()
|
self.is_index = isinstance(definition["column"], int)
|
||||||
|
if self.is_index:
|
||||||
|
self.column = definition["column"] - 1 # convert to 0-based index
|
||||||
|
else:
|
||||||
|
self.column = definition["column"].lower()
|
||||||
|
|
||||||
self.type = definition.get("type", "string")
|
self.type = definition.get("type", "string")
|
||||||
if self.name in DATE_FIELDS and self.type not in DATE_TYPES:
|
if self.name in DATE_FIELDS and self.type not in DATE_TYPES:
|
||||||
self.type = "date" # override type for known date fields
|
self.type = "date" # override type for known date fields
|
||||||
@@ -150,7 +171,7 @@ for config in endoflife.list_configs(p_filter, METHOD, m_filter):
|
|||||||
try:
|
try:
|
||||||
fields_index = {"releaseCycle": headers.index(release_cycle_field.column)}
|
fields_index = {"releaseCycle": headers.index(release_cycle_field.column)}
|
||||||
for field in fields:
|
for field in fields:
|
||||||
fields_index[field.name] = headers.index(field.column)
|
fields_index[field.name] = field.column if field.is_index else headers.index(field.column)
|
||||||
min_column_count = max(fields_index.values()) + 1
|
min_column_count = max(fields_index.values()) + 1
|
||||||
|
|
||||||
for row in table.select(rows_selector):
|
for row in table.select(rows_selector):
|
||||||
@@ -183,6 +204,5 @@ for config in endoflife.list_configs(p_filter, METHOD, m_filter):
|
|||||||
logging.info(f"removing future release '{release}'")
|
logging.info(f"removing future release '{release}'")
|
||||||
product_data.remove_release(release_name)
|
product_data.remove_release(release_name)
|
||||||
|
|
||||||
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logging.info(f"skipping table with headers {headers}: {e}")
|
logging.info(f"skipping table with headers {headers}: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user