Skip to content

Commit

Permalink
Update inst-api implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
uriyyo committed Mar 29, 2024
1 parent f15b457 commit 019a80a
Show file tree
Hide file tree
Showing 26 changed files with 854 additions and 699 deletions.
38 changes: 19 additions & 19 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
repos:
- repo: https://github.com/pre-commit/mirrors-isort
rev: v5.9.1
- repo: local
hooks:
- id: isort
- id: ruff-format
language: python
name: ruff-format
pass_filenames: false
language_version: python3.10
entry: poetry run ruff format instapi tests

- repo: https://github.com/pycqa/flake8
rev: 3.9.2
- repo: local
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear
- id: ruff
language: python
name: ruff
pass_filenames: false
language_version: python3.10
entry: poetry run ruff check --fix --exit-non-zero-on-fix --show-fixes instapi

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.910
- repo: local
hooks:
- id: mypy
exclude: tests
additional_dependencies:
- types-requests

- repo: https://github.com/ambv/black
rev: 22.3.0
hooks:
- id: black
language_version: python3.7
language: python
name: mypy
pass_filenames: false
entry: poetry run mypy --show-error-codes instapi
1 change: 1 addition & 0 deletions instapi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@
"Resources",
"User",
"Video",
"Message",
]
15 changes: 8 additions & 7 deletions instapi/cache.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from collections import deque
from collections.abc import Callable
from contextvars import ContextVar
from dataclasses import dataclass
from functools import partial, wraps
from hashlib import md5
from itertools import chain
from pathlib import Path
from time import time
from typing import Any, Callable, Deque, Dict, Optional, Tuple, TypeVar
from typing import Any, Deque, TypeVar

from instagram_private_api.http import ClientCookieJar

Expand Down Expand Up @@ -34,7 +35,7 @@ def _get_hash(credentials: Credentials) -> str: # pragma: no cover


# TODO: add tests for cache logic
def get_from_cache(credentials: Credentials) -> Optional[bytes]: # pragma: no cover
def get_from_cache(credentials: Credentials) -> bytes | None: # pragma: no cover
cache = _CACHE_ROOT / _get_hash(credentials)
return cache.read_bytes() if cache.exists() else None

Expand All @@ -45,20 +46,20 @@ def write_to_cache(credentials: Credentials, cookie: ClientCookieJar) -> None:


CACHED_TIME = ContextVar("CACHED_TIME", default=60)
CacheKey = Tuple[Tuple, Tuple]
CacheKey = tuple[tuple[Any, ...], tuple[Any, ...]]

T = TypeVar("T")


@dataclass
class _CacheInfo:
cache: Dict[CacheKey, Any]
keys: Deque[Tuple[CacheKey, float]]
cache: dict[CacheKey, Any]
keys: Deque[tuple[CacheKey, float]]


def cached(func: Callable[..., T]) -> Callable[..., T]:
cache: Dict[CacheKey, Any] = {}
keys: Deque[Tuple[CacheKey, float]] = deque()
cache: dict[CacheKey, Any] = {}
keys: Deque[tuple[CacheKey, float]] = deque()

def _delete_expired_keys() -> None: # pragma: no cover
while keys:
Expand Down
10 changes: 5 additions & 5 deletions instapi/client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import ssl
from dataclasses import dataclass
from typing import Any, ClassVar, Optional, cast
from typing import Any, ClassVar, cast

from instagram_private_api import ClientError

Expand All @@ -17,7 +17,7 @@

@dataclass
class ClientProxy:
obj: Optional[Client] = None
obj: Client | None = None

# Used to return dummy implementation of methods
is_testing: ClassVar[bool] = False
Expand All @@ -27,7 +27,7 @@ def __getattr__(self, item: str) -> Any:
if self.is_testing:
return None

raise ClientNotInitedException()
raise ClientNotInitedException

return getattr(self.obj, item)

Expand All @@ -36,8 +36,8 @@ def __getattr__(self, item: str) -> Any:


def bind(
username: Optional[str] = ENV_USERNAME,
password: Optional[str] = ENV_PASSWORD,
username: str | None = ENV_USERNAME,
password: str | None = ENV_PASSWORD,
) -> None:
if username is None or password is None:
raise ValueError("Both username and password should be passed")
Expand Down
8 changes: 4 additions & 4 deletions instapi/client_api/base.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
from typing import Optional, cast
from typing import cast

from instagram_private_api import Client

from ..types import StrDict


class BaseClient(Client):
class BaseClient(Client): # type: ignore[misc]
def _call_api(
self,
endpoint: str,
params: Optional[StrDict] = None,
query: Optional[StrDict] = None,
params: StrDict | None = None,
query: StrDict | None = None,
return_response: bool = False,
unsigned: bool = False,
version: str = "v1",
Expand Down
23 changes: 12 additions & 11 deletions instapi/client_api/direct.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from typing import Iterable, Optional, Union, cast
from collections.abc import Iterable
from typing import Any, SupportsInt, Union, cast

import requests
from instagram_private_api.errors import ClientError

from ..types import StrDict, SupportsInt_co
from ..types import StrDict
from ..utils import join
from .base import BaseClient

RecipientUsers = Union[SupportsInt_co, Iterable[SupportsInt_co]]
RecipientUsers = Union[SupportsInt, Iterable[SupportsInt]]


class DirectEndpoint(BaseClient):
Expand All @@ -17,7 +18,7 @@ def _convert_recipient_users(
braces_count: int = 2,
) -> str:
try:
value = join(map(int, cast(Iterable, recipient_users)))
value = join(map(int, cast(Iterable[Any], recipient_users)))
except TypeError:
value = str(int(cast(str, recipient_users)))

Expand All @@ -26,7 +27,7 @@ def _convert_recipient_users(
def direct_v2_send_item(
self,
recipient_users: RecipientUsers,
thread_id: int = None,
thread_id: int | None = None,
*,
item_type: str,
item_data: StrDict,
Expand Down Expand Up @@ -56,14 +57,14 @@ def direct_v2_send_item(
try:
response.raise_for_status()
except requests.HTTPError as e:
raise ClientError(str(e), response.status_code, response.text)
raise ClientError(str(e), response.status_code, response.text) from e

return cast(StrDict, response.json())

def direct_v2_send_text(
self,
recipient_users: RecipientUsers = (),
thread_id: int = None,
thread_id: int | None = None,
*,
text: str,
) -> StrDict:
Expand All @@ -77,7 +78,7 @@ def direct_v2_send_text(
def direct_v2_send_link(
self,
recipient_users: RecipientUsers = (),
thread_id: Optional[int] = None,
thread_id: int | None = None,
*,
text: str = "",
link: str,
Expand All @@ -95,7 +96,7 @@ def direct_v2_send_link(
def direct_v2_send_media_share(
self,
recipient_users: RecipientUsers = (),
thread_id: Optional[int] = None,
thread_id: int | None = None,
*,
text: str = "",
media_type: str = "photo",
Expand All @@ -115,7 +116,7 @@ def direct_v2_send_media_share(
def direct_v2_send_hashtag(
self,
recipient_users: RecipientUsers = (),
thread_id: Optional[int] = None,
thread_id: int | None = None,
*,
text: str = "",
hashtag: str,
Expand All @@ -133,7 +134,7 @@ def direct_v2_send_hashtag(
def direct_v2_send_profile(
self,
recipient_users: RecipientUsers = (),
thread_id: Optional[int] = None,
thread_id: int | None = None,
*,
text: str = "",
profile_id: int,
Expand Down
27 changes: 13 additions & 14 deletions instapi/models/base.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
from __future__ import annotations

from dataclasses import asdict, dataclass, field, fields
from typing import AbstractSet, Any, Type, TypeVar, cast
from dataclasses import Field, asdict, dataclass, field, fields
from typing import AbstractSet, Any

from ..types import StrDict
from typing_extensions import Self, dataclass_transform

ModelT_co = TypeVar("ModelT_co", bound="BaseModel", covariant=True)
from ..types import StrDict


@dataclass_transform(
field_specifiers=(field, Field),
)
class BaseModelMeta(type):
def __new__(mcs, *args: Any, **kwargs: Any) -> Any:
cls = super().__new__(mcs, *args, **kwargs)

try:
dataclass_kwargs = cls.Config.dataclass_kwargs # noqa
dataclass_kwargs = cls.Config.dataclass_kwargs
except AttributeError:
dataclass_kwargs = {}

Expand All @@ -26,9 +29,9 @@ def fields(cls) -> AbstractSet[str]:
return {f.name for f in fields(cls)} - {"__dataclass_fields__"}

@classmethod
def create(cls: Type[ModelT_co], data: Any) -> ModelT_co:
def create(cls, data: Any) -> Self:
# noinspection PyArgumentList
return cast(ModelT_co, cls(**{k: data[k] for k in cls.fields() if k in data})) # type: ignore
return cls(**{k: data[k] for k in cls.fields() if k in data})

def as_dict(self) -> StrDict:
"""
Expand All @@ -38,10 +41,7 @@ def as_dict(self) -> StrDict:
:return: native instagram representation
"""
return {
key: value.as_dict() if isinstance(value, BaseModel) else value
for key, value in asdict(self).items()
}
return {key: value.as_dict() if isinstance(value, BaseModel) else value for key, value in asdict(self).items()}


class Entity(BaseModel):
Expand All @@ -54,12 +54,11 @@ def __int__(self) -> int:
return self.pk

@classmethod
def create(cls: Type[ModelT_co], data: StrDict) -> ModelT_co:
return super().create(data) # type: ignore
def create(cls, data: StrDict) -> Self:
return super().create(data)


__all__ = [
"BaseModel",
"Entity",
"ModelT_co",
]
Loading

0 comments on commit 019a80a

Please sign in to comment.