Skip to content

Commit

Permalink
Merge pull request #287 from mesozoic/collaborator_model
Browse files Browse the repository at this point in the history
Introduce "Collaborator" model
  • Loading branch information
mesozoic committed Jul 31, 2023
2 parents a3b471a + 855177b commit 8fea65a
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 24 deletions.
2 changes: 2 additions & 0 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ Module: pyairtable.models

.. autoclass:: pyairtable.models.Comment
:members:
.. autoclass:: pyairtable.models.Collaborator
:members:

Module: pyairtable.orm
*******************************
Expand Down
10 changes: 5 additions & 5 deletions docs/source/orm.rst
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,11 @@ comments on a particular record, just like their :class:`~pyairtable.Table` equi
type='user'
)
},
author={
'id': 'usr0000pyairtable',
'email': 'pyairtable@example.com',
'name': 'Your pyairtable access token'
}
author=Collaborator(
id='usr0000pyairtable',
email='pyairtable@example.com',
name='Your pyairtable access token'
)
)
]
>>> comment.text = "Never mind!"
Expand Down
10 changes: 5 additions & 5 deletions docs/source/tables.rst
Original file line number Diff line number Diff line change
Expand Up @@ -297,11 +297,11 @@ and :meth:`~pyairtable.Table.add_comment` methods will return instances of
type='user'
)
},
author={
'id': 'usr0000pyairtable',
'email': 'pyairtable@example.com',
'name': 'Your pyairtable access token'
}
author=Collaborator(
id='usr0000pyairtable',
email='pyairtable@example.com',
name='Your pyairtable access token'
)
)
]
>>> comment.text = "Never mind!"
Expand Down
10 changes: 5 additions & 5 deletions pyairtable/api/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,11 +489,11 @@ def comments(self, record_id: RecordId) -> List["pyairtable.models.Comment"]:
type='user'
)
},
author={
'id': 'usr0000pyairtable',
'email': 'pyairtable@example.com',
'name': 'Your pyairtable access token'
}
author=Collaborator(
id='usr0000pyairtable',
email='pyairtable@example.com',
name='Your pyairtable access token'
)
)
]
Expand Down
2 changes: 2 additions & 0 deletions pyairtable/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from .collaborator import Collaborator
from .comment import Comment

__all__ = [
"Collaborator",
"Comment",
]
26 changes: 26 additions & 0 deletions pyairtable/models/collaborator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from typing import Optional

from typing_extensions import TypeAlias

from ._base import AirtableModel

UserId: TypeAlias = str


class Collaborator(AirtableModel):
"""
Represents an Airtable user being passed from the API.
This is only used in contexts involving other models (e.g. :class:`~pyairtable.models.Comment`).
In contexts where API values are returned as ``dict``, we will return
collaborator information as a ``dict`` as well.
"""

#: Airtable's unique ID for the user, in the format ``usrXXXXXXXXXXXXXX``.
id: UserId

#: The email address of the user.
email: Optional[str]

#: The display name of the user.
name: Optional[str]
16 changes: 8 additions & 8 deletions pyairtable/models/comment.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Dict, Optional

from pyairtable.api.types import CollaboratorDict
from pyairtable.models._base import AirtableModel, SerializableModel
from ._base import AirtableModel, SerializableModel
from .collaborator import Collaborator


class Comment(SerializableModel):
Expand All @@ -24,11 +24,11 @@ class Comment(SerializableModel):
type='user'
)
},
author={
'id': 'usrL2xZC5xoH4luAi',
'email': 'pyairtable@example.com',
'name': 'Your pyairtable access token'
}
author=Collaborator(
id='usr0000pyairtable',
email='pyairtable@example.com',
name='Your pyairtable access token'
)
)
]
>>> comment.text = "Never mind!"
Expand All @@ -51,7 +51,7 @@ class Comment(SerializableModel):
last_updated_time: Optional[str]

#: The account which created the comment.
author: CollaboratorDict
author: Collaborator

#: Users or groups that were mentioned in the text.
mentioned: Optional[Dict[str, "Comment.Mentioned"]]
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/test_integration_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ def test_integration_comments(api, table: Table, cols):
comments = table.comments(record["id"])
assert len(comments) == 1
assert whoami in comments[0].text
assert comments[0].author
assert comments[0].author.id == whoami
assert comments[0].mentioned[whoami].id == whoami

# Test that we can modify the comment and examine its updated state
Expand Down
29 changes: 29 additions & 0 deletions tests/test_models_collaborator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import pytest

from pyairtable.models import Collaborator

fake_user_data = {
"id": "usr000000fakeuser",
"email": "fake@example.com",
"name": "Fake User",
}


def test_parse():
user = Collaborator.parse_obj(fake_user_data)
assert user.id == fake_user_data["id"]
assert user.email == fake_user_data["email"]
assert user.name == fake_user_data["name"]


def test_init():
c = Collaborator(id="usrXXXXXXXXXXXXX")
assert c.id == "usrXXXXXXXXXXXXX"
assert c.email is None
assert c.name is None

with pytest.raises(ValueError):
Collaborator()

with pytest.raises(ValueError):
Collaborator(name="Fake User")
11 changes: 11 additions & 0 deletions tests/test_models_comment.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ def test_parse(comment_json):
Comment.parse_obj(comment_json)


@pytest.mark.parametrize("attr", ["mentioned", "last_updated_time"])
def test_missing_attributes(comment_json, attr):
"""
Test that we can parse the payload when missing optional values.
"""
del comment_json[Comment.__fields__[attr].alias]
comment = Comment.parse_obj(comment_json)
assert getattr(comment, attr) is None


@pytest.mark.parametrize(
"attr,value",
[
Expand Down Expand Up @@ -82,6 +92,7 @@ def test_save(comment, requests_mock):

# ...but our model loaded whatever values the API sent back.
assert comment.text == new_text
assert comment.author.email == "author@example.com"
assert not comment.mentioned


Expand Down

0 comments on commit 8fea65a

Please sign in to comment.