зеркало из
https://github.com/viginum-datalab/twscrape.git
synced 2025-10-29 05:04:22 +02:00
add missing string id representation to models #116
Этот коммит содержится в:
родитель
748ceae053
Коммит
277ebd1649
Двоичные данные
.github/example.png
поставляемый
Обычный файл
Двоичные данные
.github/example.png
поставляемый
Обычный файл
Двоичный файл не отображается.
|
После Ширина: | Высота: | Размер: 218 KiB |
@ -13,7 +13,7 @@
|
|||||||
Twitter GraphQL API implementation with [SNScrape](https://github.com/JustAnotherArchivist/snscrape) data models.
|
Twitter GraphQL API implementation with [SNScrape](https://github.com/JustAnotherArchivist/snscrape) data models.
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*0erkeMBhl_qqRofIeU5jMQ.png" alt="example of cli usage" width="560px">
|
<img src=".github/example.png" alt="example of cli usage" width="560px">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|||||||
@ -4,7 +4,7 @@ from typing import Callable
|
|||||||
|
|
||||||
from twscrape import API, gather
|
from twscrape import API, gather
|
||||||
from twscrape.logger import set_log_level
|
from twscrape.logger import set_log_level
|
||||||
from twscrape.models import Tweet, User, parse_tweet
|
from twscrape.models import Tweet, User, UserRef, parse_tweet
|
||||||
|
|
||||||
BASE_DIR = os.path.dirname(__file__)
|
BASE_DIR = os.path.dirname(__file__)
|
||||||
DATA_DIR = os.path.join(BASE_DIR, "mocked-data")
|
DATA_DIR = os.path.join(BASE_DIR, "mocked-data")
|
||||||
@ -49,18 +49,33 @@ def mock_rep(fn: Callable, filename: str, as_generator=False):
|
|||||||
|
|
||||||
def check_tweet(doc: Tweet | None):
|
def check_tweet(doc: Tweet | None):
|
||||||
assert doc is not None
|
assert doc is not None
|
||||||
assert doc.id is not None
|
|
||||||
assert doc.id_str is not None
|
|
||||||
assert isinstance(doc.id, int)
|
assert isinstance(doc.id, int)
|
||||||
assert isinstance(doc.id_str, str)
|
assert isinstance(doc.id_str, str)
|
||||||
assert doc.id == int(doc.id_str)
|
assert str(doc.id) == doc.id_str
|
||||||
|
|
||||||
assert doc.url is not None
|
assert doc.url is not None
|
||||||
assert doc.id_str in doc.url
|
assert doc.id_str in doc.url
|
||||||
assert doc.user is not None
|
assert doc.user is not None
|
||||||
|
|
||||||
|
assert isinstance(doc.conversationId, int)
|
||||||
|
assert isinstance(doc.conversationIdStr, str)
|
||||||
|
assert str(doc.conversationId) == doc.conversationIdStr
|
||||||
|
|
||||||
|
if doc.inReplyToTweetId is not None:
|
||||||
|
assert isinstance(doc.inReplyToTweetId, int)
|
||||||
|
assert isinstance(doc.inReplyToTweetIdStr, str)
|
||||||
|
assert str(doc.inReplyToTweetId) == doc.inReplyToTweetIdStr
|
||||||
|
|
||||||
|
if doc.inReplyToUser:
|
||||||
|
check_user_ref(doc.inReplyToUser)
|
||||||
|
|
||||||
|
if doc.mentionedUsers:
|
||||||
|
for x in doc.mentionedUsers:
|
||||||
|
check_user_ref(x)
|
||||||
|
|
||||||
obj = doc.dict()
|
obj = doc.dict()
|
||||||
assert doc.id == obj["id"]
|
assert doc.id == obj["id"]
|
||||||
|
assert doc.id_str == obj["id_str"]
|
||||||
assert doc.user.id == obj["user"]["id"]
|
assert doc.user.id == obj["user"]["id"]
|
||||||
|
|
||||||
assert "url" in obj
|
assert "url" in obj
|
||||||
@ -104,10 +119,9 @@ def check_tweet(doc: Tweet | None):
|
|||||||
|
|
||||||
def check_user(doc: User):
|
def check_user(doc: User):
|
||||||
assert doc.id is not None
|
assert doc.id is not None
|
||||||
assert doc.id_str is not None
|
|
||||||
assert isinstance(doc.id, int)
|
assert isinstance(doc.id, int)
|
||||||
assert isinstance(doc.id_str, str)
|
assert isinstance(doc.id_str, str)
|
||||||
assert doc.id == int(doc.id_str)
|
assert str(doc.id) == doc.id_str
|
||||||
|
|
||||||
assert doc.username is not None
|
assert doc.username is not None
|
||||||
assert doc.descriptionLinks is not None
|
assert doc.descriptionLinks is not None
|
||||||
@ -127,6 +141,19 @@ def check_user(doc: User):
|
|||||||
assert str(doc.id) in txt
|
assert str(doc.id) in txt
|
||||||
|
|
||||||
|
|
||||||
|
def check_user_ref(doc: UserRef):
|
||||||
|
assert isinstance(doc.id, int)
|
||||||
|
assert isinstance(doc.id_str, str)
|
||||||
|
assert str(doc.id) == doc.id_str
|
||||||
|
|
||||||
|
assert doc.username is not None
|
||||||
|
assert doc.displayname is not None
|
||||||
|
|
||||||
|
obj = doc.dict()
|
||||||
|
assert doc.id == obj["id"]
|
||||||
|
assert doc.id_str == obj["id_str"]
|
||||||
|
|
||||||
|
|
||||||
async def test_search():
|
async def test_search():
|
||||||
api = API()
|
api = API()
|
||||||
mock_rep(api.search_raw, "raw_search", as_generator=True)
|
mock_rep(api.search_raw, "raw_search", as_generator=True)
|
||||||
|
|||||||
@ -84,13 +84,19 @@ class TextLink(JSONTrait):
|
|||||||
@dataclass
|
@dataclass
|
||||||
class UserRef(JSONTrait):
|
class UserRef(JSONTrait):
|
||||||
id: int
|
id: int
|
||||||
|
id_str: str
|
||||||
username: str
|
username: str
|
||||||
displayname: str
|
displayname: str
|
||||||
_type: str = "snscrape.modules.twitter.UserRef"
|
_type: str = "snscrape.modules.twitter.UserRef"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse(obj: dict):
|
def parse(obj: dict):
|
||||||
return UserRef(id=int(obj["id_str"]), username=obj["screen_name"], displayname=obj["name"])
|
return UserRef(
|
||||||
|
id=int(obj["id_str"]),
|
||||||
|
id_str=obj["id_str"],
|
||||||
|
username=obj["screen_name"],
|
||||||
|
displayname=obj["name"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -163,6 +169,7 @@ class Tweet(JSONTrait):
|
|||||||
likeCount: int
|
likeCount: int
|
||||||
quoteCount: int
|
quoteCount: int
|
||||||
conversationId: int
|
conversationId: int
|
||||||
|
conversationIdStr: str
|
||||||
hashtags: list[str]
|
hashtags: list[str]
|
||||||
cashtags: list[str]
|
cashtags: list[str]
|
||||||
mentionedUsers: list[UserRef]
|
mentionedUsers: list[UserRef]
|
||||||
@ -173,6 +180,7 @@ class Tweet(JSONTrait):
|
|||||||
place: Optional[Place] = None
|
place: Optional[Place] = None
|
||||||
coordinates: Optional[Coordinates] = None
|
coordinates: Optional[Coordinates] = None
|
||||||
inReplyToTweetId: int | None = None
|
inReplyToTweetId: int | None = None
|
||||||
|
inReplyToTweetIdStr: str | None = None
|
||||||
inReplyToUser: UserRef | None = None
|
inReplyToUser: UserRef | None = None
|
||||||
source: str | None = None
|
source: str | None = None
|
||||||
sourceUrl: str | None = None
|
sourceUrl: str | None = None
|
||||||
@ -217,6 +225,7 @@ class Tweet(JSONTrait):
|
|||||||
likeCount=obj["favorite_count"],
|
likeCount=obj["favorite_count"],
|
||||||
quoteCount=obj["quote_count"],
|
quoteCount=obj["quote_count"],
|
||||||
conversationId=int(obj["conversation_id_str"]),
|
conversationId=int(obj["conversation_id_str"]),
|
||||||
|
conversationIdStr=obj["conversation_id_str"],
|
||||||
hashtags=[x["text"] for x in get_or(obj, "entities.hashtags", [])],
|
hashtags=[x["text"] for x in get_or(obj, "entities.hashtags", [])],
|
||||||
cashtags=[x["text"] for x in get_or(obj, "entities.symbols", [])],
|
cashtags=[x["text"] for x in get_or(obj, "entities.symbols", [])],
|
||||||
mentionedUsers=[UserRef.parse(x) for x in get_or(obj, "entities.user_mentions", [])],
|
mentionedUsers=[UserRef.parse(x) for x in get_or(obj, "entities.user_mentions", [])],
|
||||||
@ -229,6 +238,7 @@ class Tweet(JSONTrait):
|
|||||||
place=Place.parse(obj["place"]) if obj.get("place") else None,
|
place=Place.parse(obj["place"]) if obj.get("place") else None,
|
||||||
coordinates=Coordinates.parse(obj),
|
coordinates=Coordinates.parse(obj),
|
||||||
inReplyToTweetId=int_or(obj, "in_reply_to_status_id_str"),
|
inReplyToTweetId=int_or(obj, "in_reply_to_status_id_str"),
|
||||||
|
inReplyToTweetIdStr=get_or(obj, "in_reply_to_status_id_str"),
|
||||||
inReplyToUser=_get_reply_user(obj, res),
|
inReplyToUser=_get_reply_user(obj, res),
|
||||||
source=obj.get("source", None),
|
source=obj.get("source", None),
|
||||||
sourceUrl=_get_source_url(obj),
|
sourceUrl=_get_source_url(obj),
|
||||||
|
|||||||
Загрузка…
x
Ссылка в новой задаче
Block a user