Skip to content

Commit 5232369

Browse files
authored
Merge pull request #253 from networktocode/release-v2.3.0
Release v2.3.0
2 parents f58f75e + 8aba20d commit 5232369

24 files changed

+1471
-652
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ jobs:
113113
strategy:
114114
fail-fast: true
115115
matrix:
116-
python-version: ["3.7", "3.8", "3.9", "3.10"]
116+
python-version: ["3.8", "3.9", "3.10", "3.11"]
117117
runs-on: "ubuntu-20.04"
118118
env:
119119
INVOKE_LOCAL: "True"

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# Changelog
22

3+
## v2.3.0 - 2023-12-15
4+
5+
### Added
6+
7+
- [#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
8+
9+
- [#249](https://github.com/networktocode/circuit-maintenance-parser/pull/249) - Add Metadata to every Maintenance, addresses issue #246 by @chadell
10+
11+
### Changed
12+
13+
- [#237](https://github.com/networktocode/circuit-maintenance-parser/pull/237) - Remove Python 3.7 support by @slyngshede
14+
15+
### Fixed
16+
17+
- [#243](https://github.com/networktocode/circuit-maintenance-parser/pull/243) - Handle broken EUNetworks cancellation messages by @jmaslak
18+
- [#251](https://github.com/networktocode/circuit-maintenance-parser/pull/251) Add missing Arelion entry to SUPPORTED_PROVIDERS by @glennmatthews
19+
320
## v2.2.4 - 2023-07-12
421

522
- #230 - Swap out tzwhere for TimezoneFinder

README.md

Lines changed: 59 additions & 20 deletions
Large diffs are not rendered by default.

circuit_maintenance_parser/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from .provider import (
88
GenericProvider,
99
AquaComms,
10+
Arelion,
1011
AWS,
1112
BSO,
1213
Cogent,
@@ -32,6 +33,7 @@
3233
SUPPORTED_PROVIDERS = (
3334
GenericProvider,
3435
AquaComms,
36+
Arelion,
3537
AWS,
3638
BSO,
3739
Cogent,

circuit_maintenance_parser/cli.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,5 @@ def main(provider_type, data_file, data_type, verbose):
5252
for idx, parsed_notification in enumerate(parsed_notifications):
5353
click.secho(f"Circuit Maintenance Notification #{idx}", fg="green", bold=True)
5454
click.secho(parsed_notification.to_json(), fg="yellow")
55+
click.secho(f"Metadata #{idx}", fg="green", bold=True)
56+
click.secho(parsed_notification.metadata, fg="blue")

circuit_maintenance_parser/output.py

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from typing import List
1010

11-
from pydantic import BaseModel, validator, StrictStr, StrictInt, Extra
11+
from pydantic import BaseModel, validator, StrictStr, StrictInt, Extra, PrivateAttr
1212

1313

1414
class Impact(str, Enum):
@@ -82,7 +82,7 @@ class CircuitImpact(BaseModel, extra=Extra.forbid):
8282
# Optional Attributes
8383
impact: Impact = Impact.OUTAGE
8484

85-
# pylint: disable=no-self-argument,no-self-use
85+
# pylint: disable=no-self-argument
8686
@validator("impact")
8787
def validate_impact_type(cls, value):
8888
"""Validate Impact type."""
@@ -91,27 +91,42 @@ def validate_impact_type(cls, value):
9191
return value
9292

9393

94+
class Metadata(BaseModel):
95+
"""Metadata class to provide context about the Maintenance object."""
96+
97+
provider: StrictStr
98+
processor: StrictStr
99+
parsers: List[StrictStr]
100+
generated_by_llm: bool = False
101+
102+
94103
class Maintenance(BaseModel, extra=Extra.forbid):
95104
"""Maintenance class.
96105
97106
Mandatory attributes:
98107
provider: identifies the provider of the service that is the subject of the maintenance notification
99108
account: identifies an account associated with the service that is the subject of the maintenance notification
100109
maintenance_id: contains text that uniquely identifies the maintenance that is the subject of the notification
101-
circuits: list of circuits affected by the maintenance notification and their specific impact
110+
circuits: list of circuits affected by the maintenance notification and their specific impact. Note this can be
111+
an empty list for notifications with a CANCELLED status if the provider does not populate the circuit list.
112+
status: defines the overall status or confirmation for the maintenance
102113
start: timestamp that defines the start date of the maintenance in GMT
103114
end: timestamp that defines the end date of the maintenance in GMT
104115
stamp: timestamp that defines the update date of the maintenance in GMT
105116
organizer: defines the contact information included in the original notification
106117
107118
Optional attributes:
108-
status: defines the overall status or confirmation for the maintenance
109119
summary: description of the maintenace notification
110120
uid: specific unique identifier for each notification
111121
sequence: sequence number - initially zero - to serialize updates in case they are received or processed out of
112122
order
113123
114124
Example:
125+
>>> metadata = Metadata(
126+
... processor="SimpleProcessor",
127+
... provider="genericprovider",
128+
... parsers=["EmailDateParser"]
129+
... )
115130
>>> Maintenance(
116131
... account="12345000",
117132
... end=1533712380,
@@ -125,26 +140,33 @@ class Maintenance(BaseModel, extra=Extra.forbid):
125140
... status="COMPLETED",
126141
... summary="This is a maintenance notification",
127142
... uid="1111",
143+
... _metadata=metadata,
128144
... )
129-
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='myemail@example.com', status=<Status.COMPLETED: 'COMPLETED'>, uid='1111', sequence=1, summary='This is a maintenance notification')
145+
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='myemail@example.com', uid='1111', sequence=1, summary='This is a maintenance notification')
130146
"""
131147

132148
provider: StrictStr
133149
account: StrictStr
134150
maintenance_id: StrictStr
151+
status: Status
135152
circuits: List[CircuitImpact]
136153
start: StrictInt
137154
end: StrictInt
138155
stamp: StrictInt
139156
organizer: StrictStr
140-
status: Status
157+
_metadata: Metadata = PrivateAttr()
141158

142159
# Non mandatory attributes
143160
uid: StrictStr = "0"
144161
sequence: StrictInt = 1
145162
summary: StrictStr = ""
146163

147-
# pylint: disable=no-self-argument,no-self-use
164+
def __init__(self, **data):
165+
"""Initialize the Maintenance object."""
166+
self._metadata = data.pop("_metadata")
167+
super().__init__(**data)
168+
169+
# pylint: disable=no-self-argument
148170
@validator("status")
149171
def validate_status_type(cls, value):
150172
"""Validate Status type."""
@@ -160,9 +182,9 @@ def validate_empty_strings(cls, value):
160182
return value
161183

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

@@ -184,3 +206,8 @@ def slug(self) -> str:
184206
def to_json(self) -> str:
185207
"""Get JSON representation of the class object."""
186208
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=2)
209+
210+
@property
211+
def metadata(self):
212+
"""Get Maintenance Metadata."""
213+
return self._metadata

0 commit comments

Comments
 (0)