Skip to content

Commit

Permalink
Merge pull request #253 from networktocode/release-v2.3.0
Browse files Browse the repository at this point in the history
Release v2.3.0
  • Loading branch information
chadell authored Dec 15, 2023
2 parents f58f75e + 8aba20d commit 5232369
Show file tree
Hide file tree
Showing 24 changed files with 1,471 additions and 652 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ jobs:
strategy:
fail-fast: true
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
python-version: ["3.8", "3.9", "3.10", "3.11"]
runs-on: "ubuntu-20.04"
env:
INVOKE_LOCAL: "True"
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Changelog

## v2.3.0 - 2023-12-15

### Added

- [#245](https://github.com/networktocode/circuit-maintenance-parser/pull/245) [#250](https://github.com/networktocode/circuit-maintenance-parser/pull/250) [#252](https://github.com/networktocode/circuit-maintenance-parser/pull/252) - OpenAI parser by @chadell

- [#249](https://github.com/networktocode/circuit-maintenance-parser/pull/249) - Add Metadata to every Maintenance, addresses issue #246 by @chadell

### Changed

- [#237](https://github.com/networktocode/circuit-maintenance-parser/pull/237) - Remove Python 3.7 support by @slyngshede

### Fixed

- [#243](https://github.com/networktocode/circuit-maintenance-parser/pull/243) - Handle broken EUNetworks cancellation messages by @jmaslak
- [#251](https://github.com/networktocode/circuit-maintenance-parser/pull/251) Add missing Arelion entry to SUPPORTED_PROVIDERS by @glennmatthews

## v2.2.4 - 2023-07-12

- #230 - Swap out tzwhere for TimezoneFinder
Expand Down
79 changes: 59 additions & 20 deletions README.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions circuit_maintenance_parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .provider import (
GenericProvider,
AquaComms,
Arelion,
AWS,
BSO,
Cogent,
Expand All @@ -32,6 +33,7 @@
SUPPORTED_PROVIDERS = (
GenericProvider,
AquaComms,
Arelion,
AWS,
BSO,
Cogent,
Expand Down
2 changes: 2 additions & 0 deletions circuit_maintenance_parser/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,5 @@ def main(provider_type, data_file, data_type, verbose):
for idx, parsed_notification in enumerate(parsed_notifications):
click.secho(f"Circuit Maintenance Notification #{idx}", fg="green", bold=True)
click.secho(parsed_notification.to_json(), fg="yellow")
click.secho(f"Metadata #{idx}", fg="green", bold=True)
click.secho(parsed_notification.metadata, fg="blue")
47 changes: 37 additions & 10 deletions circuit_maintenance_parser/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from typing import List

from pydantic import BaseModel, validator, StrictStr, StrictInt, Extra
from pydantic import BaseModel, validator, StrictStr, StrictInt, Extra, PrivateAttr


class Impact(str, Enum):
Expand Down Expand Up @@ -82,7 +82,7 @@ class CircuitImpact(BaseModel, extra=Extra.forbid):
# Optional Attributes
impact: Impact = Impact.OUTAGE

# pylint: disable=no-self-argument,no-self-use
# pylint: disable=no-self-argument
@validator("impact")
def validate_impact_type(cls, value):
"""Validate Impact type."""
Expand All @@ -91,27 +91,42 @@ def validate_impact_type(cls, value):
return value


class Metadata(BaseModel):
"""Metadata class to provide context about the Maintenance object."""

provider: StrictStr
processor: StrictStr
parsers: List[StrictStr]
generated_by_llm: bool = False


class Maintenance(BaseModel, extra=Extra.forbid):
"""Maintenance class.
Mandatory attributes:
provider: identifies the provider of the service that is the subject of the maintenance notification
account: identifies an account associated with the service that is the subject of the maintenance notification
maintenance_id: contains text that uniquely identifies the maintenance that is the subject of the notification
circuits: list of circuits affected by the maintenance notification and their specific impact
circuits: list of circuits affected by the maintenance notification and their specific impact. Note this can be
an empty list for notifications with a CANCELLED status if the provider does not populate the circuit list.
status: defines the overall status or confirmation for the maintenance
start: timestamp that defines the start date of the maintenance in GMT
end: timestamp that defines the end date of the maintenance in GMT
stamp: timestamp that defines the update date of the maintenance in GMT
organizer: defines the contact information included in the original notification
Optional attributes:
status: defines the overall status or confirmation for the maintenance
summary: description of the maintenace notification
uid: specific unique identifier for each notification
sequence: sequence number - initially zero - to serialize updates in case they are received or processed out of
order
Example:
>>> metadata = Metadata(
... processor="SimpleProcessor",
... provider="genericprovider",
... parsers=["EmailDateParser"]
... )
>>> Maintenance(
... account="12345000",
... end=1533712380,
Expand All @@ -125,26 +140,33 @@ class Maintenance(BaseModel, extra=Extra.forbid):
... status="COMPLETED",
... summary="This is a maintenance notification",
... uid="1111",
... _metadata=metadata,
... )
Maintenance(provider='A random NSP', account='12345000', maintenance_id='VNOC-1-99999999999', circuits=[CircuitImpact(circuit_id='123', impact=<Impact.NO_IMPACT: 'NO-IMPACT'>), CircuitImpact(circuit_id='456', impact=<Impact.OUTAGE: 'OUTAGE'>)], start=1533704400, end=1533712380, stamp=1533595768, organizer='[email protected]', status=<Status.COMPLETED: 'COMPLETED'>, uid='1111', sequence=1, summary='This is a maintenance notification')
Maintenance(provider='A random NSP', account='12345000', maintenance_id='VNOC-1-99999999999', status=<Status.COMPLETED: 'COMPLETED'>, circuits=[CircuitImpact(circuit_id='123', impact=<Impact.NO_IMPACT: 'NO-IMPACT'>), CircuitImpact(circuit_id='456', impact=<Impact.OUTAGE: 'OUTAGE'>)], start=1533704400, end=1533712380, stamp=1533595768, organizer='[email protected]', uid='1111', sequence=1, summary='This is a maintenance notification')
"""

provider: StrictStr
account: StrictStr
maintenance_id: StrictStr
status: Status
circuits: List[CircuitImpact]
start: StrictInt
end: StrictInt
stamp: StrictInt
organizer: StrictStr
status: Status
_metadata: Metadata = PrivateAttr()

# Non mandatory attributes
uid: StrictStr = "0"
sequence: StrictInt = 1
summary: StrictStr = ""

# pylint: disable=no-self-argument,no-self-use
def __init__(self, **data):
"""Initialize the Maintenance object."""
self._metadata = data.pop("_metadata")
super().__init__(**data)

# pylint: disable=no-self-argument
@validator("status")
def validate_status_type(cls, value):
"""Validate Status type."""
Expand All @@ -160,9 +182,9 @@ def validate_empty_strings(cls, value):
return value

@validator("circuits")
def validate_empty_circuits(cls, value):
"""Validate emptry strings."""
if len(value) < 1:
def validate_empty_circuits(cls, value, values):
"""Validate non-cancel notifications have a populated circuit list."""
if len(value) < 1 and values["status"] != "CANCELLED":
raise ValueError("At least one circuit has to be included in the maintenance")
return value

Expand All @@ -184,3 +206,8 @@ def slug(self) -> str:
def to_json(self) -> str:
"""Get JSON representation of the class object."""
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=2)

@property
def metadata(self):
"""Get Maintenance Metadata."""
return self._metadata
Loading

0 comments on commit 5232369

Please sign in to comment.