-
Notifications
You must be signed in to change notification settings - Fork 122
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
A few minor tweaks now that we're on Python 3.8 #890
Changes from 4 commits
8bf0b57
b2f6832
10f995d
49e6c62
5dd89a4
aef2f55
c147a57
3923f04
f26c710
1bccced
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,30 +34,31 @@ | |
from ops.framework import EventBase, EventSource, Framework, Object, ObjectEvents | ||
|
||
if TYPE_CHECKING: | ||
from typing_extensions import Literal, Required, TypedDict | ||
from typing import Literal | ||
|
||
from typing_extensions import Required, TypedDict | ||
|
||
from ops.framework import Handle, JsonObject, _SerializedData | ||
from ops.model import Container, Numerical, Relation, Storage | ||
|
||
# CharmMeta also needs these. | ||
_ActionParam = Dict[str, 'JsonObject'] # <JSON Schema definition> | ||
_ActionMetaDict = TypedDict( | ||
'_ActionMetaDict', { | ||
'title': str, | ||
'description': str, | ||
'params': Dict[str, _ActionParam], | ||
'required': List[str]}, | ||
total=False) | ||
|
||
class _ActionMetaDict(TypedDict, total=False): | ||
title: str | ||
description: str | ||
params: Dict[str, _ActionParam] | ||
required: List[str] | ||
|
||
_Scopes = Literal['global', 'container'] | ||
_RelationMetaDict = TypedDict( | ||
'_RelationMetaDict', { | ||
'interface': Required[str], | ||
'limit': int, | ||
'scope': _Scopes}, | ||
total=False) | ||
|
||
_MultipleRange = TypedDict('_MultipleRange', {'range': str}) | ||
|
||
class _RelationMetaDict(TypedDict, total=False): | ||
interface: Required[str] | ||
limit: int | ||
scope: _Scopes | ||
|
||
class _MultipleRange(TypedDict): | ||
range: str | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks weird. Why is _MultipleRange turned into a type, but _StorageMetaDict is not? Also, I think there should be another space here. Note that I didn't try validating all the changes here, I just happened to see this one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that was weird, wasn't it! It turned out it was because some are to define the shape of dicts that have "-" in their keys, like Which doesn't leave much of a change, but oh well. :-) |
||
_StorageMetaDict = TypedDict('_StorageMetaDict', { | ||
'type': Required[str], | ||
'description': int, | ||
|
@@ -69,21 +70,20 @@ | |
'multiple': _MultipleRange | ||
}) | ||
|
||
_ResourceMetaDict = TypedDict( | ||
'_ResourceMetaDict', { | ||
'type': Required[str], | ||
'filename': str, | ||
'description': str}, | ||
total=False) | ||
class _ResourceMetaDict(TypedDict, total=False): | ||
type: Required[str] | ||
filename: str | ||
description: str | ||
|
||
class _PayloadMetaDict(TypedDict): | ||
type: str | ||
|
||
_PayloadMetaDict = TypedDict('_PayloadMetaDict', {'type': str}) | ||
class _MountDict(TypedDict, total=False): | ||
storage: Required[str] | ||
location: str | ||
|
||
_MountDict = TypedDict( | ||
'_MountDict', {'storage': Required[str], | ||
'location': str}, | ||
total=False) | ||
_ContainerMetaDict = TypedDict( | ||
'_ContainerMetaDict', {'mounts': List[_MountDict]}) | ||
class _ContainerMetaDict(TypedDict): | ||
mounts: List[_MountDict] | ||
|
||
_CharmMetaDict = TypedDict( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should also be a class, vs a TypedDict instantiation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not quite sure what you mean here? |
||
'_CharmMetaDict', { # all are optional | ||
|
@@ -108,23 +108,20 @@ | |
}, total=False) | ||
|
||
# can't put in *Event because *Event.snapshot needs it. | ||
_WorkloadEventSnapshot = TypedDict('_WorkloadEventSnapshot', { | ||
'container_name': str | ||
}, total=False) | ||
class _WorkloadEventSnapshot(TypedDict, total=False): | ||
container_name: str | ||
|
||
_RelationDepartedEventSnapshot = TypedDict('_RelationDepartedEventSnapshot', { | ||
'relation_name': str, | ||
'relation_id': int, | ||
'app_name': Optional[str], | ||
'unit_name': Optional[str], | ||
'departing_unit': Optional[str] | ||
}, total=False) | ||
class _RelationDepartedEventSnapshot(TypedDict, total=False): | ||
relation_name: str | ||
relation_id: int | ||
app_name: Optional[str] | ||
unit_name: Optional[str] | ||
departing_unit: Optional[str] | ||
|
||
_StorageEventSnapshot = TypedDict('_StorageEventSnapshot', { | ||
'storage_name': str, | ||
'storage_index': int, | ||
'storage_location': str, | ||
}, total=False) | ||
class _StorageEventSnapshot(TypedDict, total=False): | ||
storage_name: str | ||
storage_index: int | ||
storage_location: str | ||
|
||
|
||
class HookEvent(EventBase): | ||
|
@@ -425,12 +422,11 @@ class RelationEvent(HookEvent): | |
|
||
""" | ||
if TYPE_CHECKING: | ||
_RelationEventSnapshot = TypedDict('_RelationEventSnapshot', { | ||
'relation_name': Required[str], | ||
'relation_id': Required[int], | ||
'app_name': Optional[str], | ||
'unit_name': Optional[str] | ||
}, total=False) | ||
class _RelationEventSnapshot(TypedDict, total=False): | ||
relation_name: Required[str] | ||
relation_id: Required[int] | ||
app_name: Optional[str] | ||
unit_name: Optional[str] | ||
|
||
def __init__(self, handle: 'Handle', relation: 'Relation', | ||
app: Optional[model.Application] = None, | ||
|
@@ -1195,7 +1191,7 @@ def __init__(self, role: RelationRole, relation_name: str, raw: '_RelationMetaDi | |
self.scope = raw.get('scope') or self._default_scope | ||
if self.scope not in self.VALID_SCOPES: | ||
raise TypeError("scope should be one of {}; not '{}'".format( | ||
', '.join("'{}'".format(s) for s in self.VALID_SCOPES), self.scope)) | ||
', '.join(f"'{s}'" for s in self.VALID_SCOPES), self.scope)) | ||
|
||
|
||
class StorageMeta: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,8 +50,7 @@ | |
|
||
if TYPE_CHECKING: | ||
from pathlib import Path | ||
|
||
from typing_extensions import Literal, Protocol, Type | ||
from typing import Literal, Protocol, Type | ||
|
||
from ops.charm import CharmMeta | ||
from ops.model import JsonObject, Model, _ModelBackend | ||
|
@@ -613,7 +612,7 @@ def __init__(self, storage: Union[SQLiteStorage, JujuStorage], | |
|
||
# Parse the env var once, which may be used multiple times later | ||
debug_at = os.environ.get('JUJU_DEBUG_AT') | ||
self._juju_debug_at = (set(x.strip() for x in debug_at.split(',')) | ||
self._juju_debug_at = ({x.strip() for x in debug_at.split(',')} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do wonder if this is actually better syntax :) But it exists, and I wouldn't block if someone was using it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, same. But speaking of better syntax, looking at it again I didn't like the nested inline if-else with set comprehension, so I've also split it onto multiple lines. Hopefully clearer now. |
||
if debug_at else set()) # type: Set[str] | ||
|
||
def set_breakpointhook(self): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -185,7 +185,7 @@ def _parse_lib(spec): | |
logger.debug(" Parsing %r", spec.name) | ||
|
||
try: | ||
with open(spec.origin, 'rt', encoding='utf-8') as f: | ||
with open(spec.origin, encoding='utf-8') as f: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feels like something that might be redundant with a default, but I don't mind being explicit to the developers as to expected behavior. Do you know why this was removed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I guess pyupgrade removes it because it's the default (now? not sure how long that's been). Read/r has been the default forever, maybe the text/t default came later. But I can see where this is debatable, so I've reverted this change and just left it explicit. |
||
libinfo = {} | ||
for n, line in enumerate(f): | ||
if len(libinfo) == len(_NEEDED_KEYS): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the first that I've seen meta arguments to classes (
total=False
).Apparently
__init_subclass__
has been a thing since about python 3.6.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the arg, I'd suspect that
TypedDict
is@dataclass
, though I haven't actually looked at the class definition.Do we have use for pseudo-metaclass stuff other than the
__set_name__
changes from the last PR (part of the same PEP as__init_subclass__
, IIRC)?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep up with the times, @jameinel. ;-) Nah, seriously, Python moves way too fast these days IMO, particularly in the typing world.