Git Product home page Git Product logo

jikanpy's Introduction

JikanPy

Travis (.com) Codecov pypi Version PyPi downloads Documentation Code style: black PRs Welcome

JikanPy is a Python wrapper for Jikan, providing bindings for all API functionality, and supports Python 3.6+. Because it is intended to be pretty much identical, please consult Jikan's documentation for thornier details on how it is meant to be used. Perhaps most importantly, JikanPy does not make any attempts to rate limit itself, so use it as responsibly as you would use the API primitively and remember that Jikan API has limitations, check out this section of documentation in order to see to what extent the API is limited or throttled.

You can use either Jikan or AioJikan depending on whether you want a synchronous wrapper class or an asynchronous wrapper class respectively. More usage examples are below.

In addition to the typical response from the Jikan API, each response contains two additional fields:

  • jikan_url: The URL that was requested; for example: https://api.jikan.moe/v4/anime/1.
  • headers: The response headers from Jikan, detailed here.

Installation

You can install the package from PyPI using pip:

$ pip install jikanpy-v4

If you have previously installed the old version of jikanpy, then make sure to uninstall the old version first:

$ pip uninstall jikanpy
$ pip install --no-cache-dir jikanpy-v4

You can also install this package directly from the source:

$ git clone https://github.com/abhinavk99/jikanpy.git 
$ cd jikanpy
$ python setup.py install

Note: This package is different from jikanpy on PyPI, which is the old Jikan v3 compatible version of jikanpy.

Usage Examples

Below are some basic examples of how to use Jikan and AioJikan. Please read the documentation below to see all the methods and more examples.

Usage Examples with Jikan

from jikanpy import Jikan
jikan = Jikan()

mushishi = jikan.anime(457)
mushishi_with_eps = jikan.anime(457, extension='episodes')

search_result = jikan.search('anime', 'Mushishi', page=2)

winter_2018_anime = jikan.seasons(year=2018, season='winter')

current_season = jikan.seasons(extension='now')

Async Usage Examples with AioJikan

import asyncio
from jikanpy import AioJikan

async def main():
    async with AioJikan() as aio_jikan:
        mushishi = await aio_jikan.anime(457)
        fma = await aio_jikan.manga(25)
        ginko = await aio_jikan.characters(425)
        kana_hanazawa = await aio_jikan.person(185)
        naruto = await aio_jikan.search(search_type='anime', query='naruto')

    # You can also construct AioJikan like below, but make sure to close the object
    aio_jikan_2 = AioJikan()
    mushishi = await aio_jikan.anime(457)
    await aio_jikan_2.close()

asyncio.run(main())

Documentation

Check out the documentation here.

Overriding default settings in Jikan and AioJikan with constructor arguments

If you're running an instance of jikan-rest on your system, and want to use that instead of api.jikan.moe, you can pass that to Jikan:

from jikanpy import Jikan
jikan = Jikan(selected_base='http://localhost:8000/v4')

If you want to use your own Requests session, you can do that too.

import requests
from jikanpy import Jikan

session = requests.Session()
# Set custom persistent headers that will be used with all HTTP requests with your session
session.headers.update({'x-test': 'true'})

jikan = Jikan(session=session)

You can use any or all of these constructor arguments when creating an instance of Jikan.

AioJikan also has selected_base and session (although AioJikan uses AioHTTP session, not Requests).

import aiohttp
import asyncio

from jikanpy import AioJikan

async def main():
    # Construct AioJikan with own base URL and custom AioHTTP session with custom persistent headers
    session = aiohttp.ClientSession(headers={'x-test': 'true'})
    aio_jikan = AioJikan(selected_base='http://localhost:8000/v4', session=session)
    await session.close()

asyncio.run(main())

Testing

# In root of repository
$ pytest -m pytest tests/
# Optionally, you can run a single test:
$ pytest -m pytest tests/test_jikan.py::test_anime_episodes_success

jikanpy's People

Contributors

abhinavk99 avatar chris-peterson444 avatar dependabot[bot] avatar emptierset avatar erayerdin avatar hajime8673 avatar iderr avatar kianmeng avatar lynbean avatar nateshoffner avatar purplepinapples avatar seanbreckenridge avatar tybug avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

jikanpy's Issues

Remove parameter checks

Currently, the code checks all the parameters that are passed in to make sure they adhere to the API, but that isn't pythonic, so it should be removed.

SyntaxError: invalid syntax

Traceback (most recent call last):
File "app.py", line 1, in
from jikanpy import Jikan
File "/home/user/venv/lib/python3.5/site-packages/jikanpy/init.py", line 3
session: requests.Session = requests.Session()
^
SyntaxError: invalid syntax

egg_info Error

Everytime i try installing this over pip it ends up giving an egg_info error:
Collecting git+git://github.com/AWConant/jikanpy.git (from -r requirements_no_audio.txt (line 7)) Cloning git://github.com/AWConant/jikanpy.git to c:\users\user\appdata\local\temp\pip-req-build-xmd4dbdu Complete output from command python setup.py egg_info: Traceback (most recent call last): File "<string>", line 1, in <module> File "C:\Users\User\AppData\Local\Programs\Python\Python35\lib\tokenize.py", line 454, in open buffer = _builtin_open(filename, 'rb') FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\User\\AppData\\Local\\Temp\\pip-req-build-xmd4dbdu\\setup.py' Command "python setup.py egg_info" failed with error code 1 in C:\Users\User\AppData\Local\Temp\pip-req-build-xmd4dbdu\

OS: Windows 10

Add remote jikan URL and repsonse headers to repsonse objects

Exposing the Jikan URL and headers could be useful if someone wants to save the remote URL to re-request at a later time, or to examine if the context has been modified (by ETag) see here

>>> cowboy_bebop = requests.get("http://api.jikan.moe/v3/anime/1")
>>> requests.get("http://api.jikan.moe/v3/anime/1", headers={"If-None-Match": cowboy_bebop.headers["ETag"]})
<Response [304]>

As discussed on the discord, this would be done by adding the headers dict to the response from jikan, perhaps as 'jikan_url' and 'jikan_headers'

What would be the preferred way to do this? Should I add a function similar to _check_response after check_response, like _add_jikan_metadata, like:

response = _add_jikan_metadata(response)

and have it add the key/vals to the dict?

Let me know and I can work on this feature this week/weekend.

Additional feature for future consideration - to allow users to pass headers or a kwarg that returns None if a 304 is returned.

Something like:

>>> j = jikanpy.Jikan()
>>> cowboy_bebop = j.anime(id=1)
>>> is_modified = j.anime(id=1, check_etag=cowboy_bebop["headers"]["ETag"])
>>> is_modified
None

If the ETag has changed since the request was last issued, is_modified would be a regular jikan response.

Alternatively/in addition, we could let users pass headers which are used, to future proof for anything that may be added. This also allows users to pass an APP_KEY that doesnt match their APP_KEY defined in .env if self-hosting, to bypass cache and re parse the page

change error message for .meta() ClientException

The typing hint for type argument in meta is Optional[int]/default is None, but if request="requests", the type is required.


meta(request: str, type: Union[str, NoneType] = None, period: Union[str, NoneType] = None, offset: Union[int, NoneType] = None) -> Dict method of jikanpy.jikan.Jikan instance
    Gets meta information regarding the Jikan REST API

    Keyword Arguments:
    request -- requests (requests, status)
    type -- type to get info on, possible values in docs
    period -- time period (today, weekly, monthly)

I realize this is because you can pass request="status", so the type/period cant be required.

The type hints would lead to believe that something like:

jikanpy.Jikan().meta(request="requests") is valid,

but that throws the error:

  File "/Users/sean/.local/share/virtualenvs/jikanpy_ext-PEUtWLmH/lib/python3.7/site-packages/jikanpy/abstractjikan.py", line 263, in _get_meta_url
    raise ClientException("Type is not valid")
jikanpy.exceptions.ClientException: Type is not valid

I dont think changing the type hints makes sense/splitting this into 2 functions makes sense, maybe an extra error check here that checks if type is None or period is None and has a better error message, like:

'type' and 'period' are required for the "request" request

would be nice.

What do you think?

Provide PyPI Package

It is possible to install Python packages via Git, but the official hosting for Python projects is PyPI.

This is not something I can do with PR though. You might want to check some documentations.

Travis also supports automatic PyPI artifact uploads if builds pass and you provide tag via Git. You can check this Travis configuration to automatize it with encrypting your password.

Or you can do it via good-old manual way as well.

This issue can wait by the way.

[Feature Request] Get affinity with friends

Hello,
First of all, thanks for this interesting project.
I'm wondering if there's a way to get affinity with friends ? If we can use this syntax and get a metric with affinity percentage of each friend that would be great i think. Maybe this issue can be flagged with improvement flag if it's not available right now.
Target code :
# friends info
myfriends = jikan.user(username='Guts__', request='friends')

But anyway great project.

Season data for animelist not available

Hi, Season name and year seems to have no data. This can be generated from the start_date field, I assume. Sorry if it's already known or reported. I've just started using this all.

from jikanpy import jikan
jikan = jikan.Jikan()
watching = jikan.user(username='skr47ch', request='animelist', argument='watching')['anime']
for anime in watching:
print(anime['airing_status']
, anime['title']
, anime['season_name']
, anime['season_year']
)

License?

Hi, I've been using this for months and only just realized this project doesn't have a License on it. Could I request we add one?

Perhaps MIT since thats what jikan uses.

@AWConant @abhinavk99

If you wish, I can make the PR

jikanpy.exceptions.APIException: 502

I can not seem to get this API to work now for some strange reason. I just made a program that used it and it worked for the time, but when I tried it again a few hours later without changing the code at all it started giving the following output.

C:\Users\<User>\Desktop\Development\mal-interface>python test.py Traceback (most recent call last): File "test.py", line 12, in <module> test() File "test.py", line 8, in test search_result = jikan.search("anime", search) File "C:\Users\<User>\AppData\Local\Programs\Python\Python38\lib\site-packages\jikanpy\jikan.py", line 67, in search return self._wrap_response(response, url, **kwargs) File "C:\Users\<User>\AppData\Local\Programs\Python\Python38\lib\site-packages\jikanpy\jikan.py", line 32, in _wrap_response self._check_response( File "C:\Users\<User>\AppData\Local\Programs\Python\Python38\lib\site-packages\jikanpy\abstractjikan.py", line 74, in _check_response raise APIException(err_str) jikanpy.exceptions.APIException: 502 : error for search type=anime, query=Fullmetal Alchemist: Brotherhood

This is the test code I put together to receive that output without all of the other code being used by my application getting in the way.

import json
from jikanpy import Jikan

def test():
# jikan = Jikan(use_ssl = True)
# jikan = Jikan(use_ssl = False)
jikan = Jikan()

search = str(input("Choose An Anime: "))
search_results = jikan.search("anime", search)
print(json.loads(json.dumps(search_results))["results"])

if __name__ == "__main__":
# main()
test()

Provide Coverage

This is a post-step of Travis. Community might want to see the percentage of covered line via tests.

Codecov is an awesome tool about this. You might want to check out.

This issue also can wait a little longer.

Provide Continuous Integration Build Status

I think it is better to provide a continuous integration build status just to inform the community about if build/tests pass or not.

TravisCI is a common CI tool for open-source project. If you allow, I can provide PR about this. You might need to create a Travis account though.

Rewrite docs

The docs right now are a bit hard to understand as they're just a list of method calls. Something like Sphinx should be used to generate documentation from docstrings.

Allow user to pass headers to jikan requests

As stated in #54, adding header support would be good to allow users to bypass caching, and compare ETag values

Current thoughts/issues:

  • I believe, coincidentally, the way I laid out _wrap_response already works for ETag checking (304s). It defaults to {}, does nothing in except block and, doesnt get modified in _check_response, and then has the headers/url added to it. So the 304 would just return a dict with the jikan_url and response headers (which I think is what we want).
json_response: Dict = {}
try:
    json_response = response.json()
except json.decoder.JSONDecodeError:
    # json failed to be parsed
    # this could happen, for example, when someone has been IP banned
    # and it returns the typical nginx 403 forbidden page
    pass
self._check_response(response_dict=json_response, response_status_code=response.status_code, **kwargs)
return self._add_jikan_metadata(response, json_response, url)
  • Add default_headers to abstractjikan? That way if someone wants to set a User-Agent to identify themselves to api.jikan.moe. Then headers passed per request can override with dict.update

Not totally sure how to implement a 304 pytest, but I'll give it a try.

No Estimate currently on when I'll have this done.

Fix ABC DeprecationWarning

DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working

Animelist paging doesn't seem to work

Hello again,
when I set the page while retrieving an animelist the number did not matter, it would always get the first page. I tried using different arguments or leaving it out completely but the issues persisted.
Here is how I tried it:
animelist = jikan.user(username='masterP', request='animelist', argument='completed', page=2) animelist = jikan.user(username='masterP', request='animelist', argument='all', page=3) animelist = jikan.user(username='masterP', request='animelist', page=4)

Jikan - Transferring to jikan.moe

Hi, can you update Jikan's base URL? Moving to api.jikan.moe.

api.jikan.me is supported until May 12th, 2018 - its' expiry.

Thanks!

Update readme for throttling

Current readme says:

Jikanpy does not make any attempts to rate limit itself, so use it as responsibly as you would use the API primitively.

However, current Jikan API documentation clearly states that it is throttled.

Will update readme.

is there a way to select the first anime listed when searching for a title?

hi, ive been trying

from jikanpy import Jikan
jikan = Jikan()
result = jikan.search("anime", "Steins Gate")
print(result)

the result i get is

{'request_hash': 'request:search:4eedd7acd468d3a389d6f1ea076ee81cd7315f50', 'request_cached': True, 'request_cache_expiry': 432000, 'results': [{'mal_id': 9253, 'url': 'https://myanimelist.net/anime/9253/Steins_Gate', 'image_url': 'https://cdn.myanimelist.net/images/anime/5/73199.jpg?s=97b97d568f25a02cf5a22dda13b5371f', 'title': 'Steins;Gate', 'airing': False, 'synopsis': 'The self-proclaimed mad scientist Rintarou Okabe rents out a room in a rickety old building in Akihabara, where he indulges himself in his hobby of inventing prospective "future gadgets" with fellow l...', 'type': 'TV', 'episodes': 24, 'score': 9.13, 'start_date': '2011-04-06T00:00:00+00:00', 'end_date': '2011-09-14T00:00:00+00:00', 'members': 1425593, 'rated': 'PG-13'}, {'mal_id': 30484, 'url': 'https://myanimelist.net/anime/30484/Steins_Gate_0', 'image_url': 'https://cdn.myanimelist.net/images/anime/1375/93521.jpg?s=d4b7e6cbc3f675048b0f1e33adefe445', 'title': 'Steins;Gate 0', 'airing': False, 'synopsis': 'The eccentric, self-proclaimed mad scientist Rintarou Okabe has become a shell of his former self. Depressed and traumatized after failing to rescue his friend Makise Kurisu, he has decided to forsake...', 'type': 'TV', 'episodes': 23, 'score': 8.53, 'start_date': '2018-04-12T00:00:00+00:00', 'end_date': '2018-09-27T00:00:00+00:00', 'members': 459124, 'rated': 'PG-13'}...

so it returns a list of all listings that match what i searched for. but i cant figure out how to select, lets say the first result, so i can get the show id. it looks like it should be result.results[0].mal_id but i cant do that, and out of the sake of just trying stuff out i tried doing it without the [0]. this may be very obvious, but i cannot figure it out

append changelog to README on pypi

don't have to bump version to include it on pypi now, though since there have been breaking API changes (and there'll be more in the future with JWT), could make sense to read CHANGELOG.md in setup.py and appending that to the the bottom of the README string here.

More user information to be made available?

I'm looking to do some trend analysis on genre and age. I know MAL makes birthdays, gender, etc. public (if the user wishes to add it to their bio). Is this data available in the API? I don't see it in the Jikan documentation under user.

jikanpy installation

Hello, I am having some issues installing this jikanpy. Most packages are supposed to have a setup.py file to help install it, but I do not see one anywhere in the file structure. Does this require some other form of installation besides pip or easy_install?

Also, does this work on python 3+, I do not see anything in the documentation

Fix aiojikan deprecation warning

All the aiojikan tests result in the warning below:

tests/test_aiojikan.py::test_anime_success
  /home/travis/build/abhinavk99/jikanpy/jikanpy/aiojikan.py:23: DeprecationWarning: The object should be created from async function
    aiohttp.ClientSession(loop=self.loop) if session is None else session
  /home/travis/virtualenv/python3.7.1/lib/python3.7/site-packages/aiohttp/connector.py:730: DeprecationWarning: The object should be created from async function
    loop=loop)
  /home/travis/virtualenv/python3.7.1/lib/python3.7/site-packages/aiohttp/connector.py:735: DeprecationWarning: The object should be created from async function
    resolver = DefaultResolver(loop=self._loop)
  /home/travis/virtualenv/python3.7.1/lib/python3.7/site-packages/aiohttp/cookiejar.py:55: DeprecationWarning: The object should be created from async function
    super().__init__(loop=loop)

Replace AbstractJikan with utility functions

Reasons

  1. AioJikan methods aren't really overriding AbstractJikan methods because async def can't override def according to mypy.
  2. AioJikan needs to reimplement methods in AbstractJikan like _wrap_response.
  3. URL getting methods in AbstractJikan can become utility functions.
  4. It'll make it easier to allow different kwargs in for session headers in the Jikan and AioJikan constructors.

genre_exclude accepts bool argument, which doesn't work

resp = j.search(
        'anime',
        '', # query string
        page=p,
        parameters={
            'genre': 12,
            'genre_exclude': True,
            'order_by': 'id',
            'sort': 'desc'})

genre_exclude should be an integer, but since bool is a subclass of integer in Python, it allows True and False, which returns incorrect results.

Get 2nd page of friends from user in myanimelist

Hello @AWConant ,
Thank you for your code, i'm currently using it to get my best affinities in my friends.
The thing is, right now, i'm only able to get affinity for my last active friends (basically page 1 of friends).
I've tried setting up a command to fetch the 2nd page of my friends :
ufriends2 = jikan.user(username='myuser', request='friends', page="2")

But it just doesn't work, it seems all it can get is the first page, which is odd in a way.
Can you tell me if i'm missing something ?
Thank you again,

selected_base not working

Locally hosting via this

import jikanpy
api = jikanpy.Jikan(selected_base="http://localhost:9000/public/v3")
api.user(username="TheSammy2010")
403 403 on https://myanimelist.net/animelist/thesammy2010/load.json?offset=0&status=7: error for username=thesammy2010, request=animelist

throws exception because it's hitting api.jikan.moe instead of localhost. Also confirmed from the docker-compose logs that no requests are made to it. Running

import requests
r = requests.get("http://localhost:9000/public/v3/user/TheSammy2010/animelist")

works fine and returns results

unexpected ClientException on manga search endpoint with genre IDs 44-45

the number of anime genres doesnt equal the number of manga genres, so trying to do a search for the manga thriller genre (45) results in an empty response

Anime Genres = 1-43
Manga Genres = 1-45

>>> j.search("manga", "Hako to Zero", parameters={'type': 'novel', 'genre': 1})["results"][0]
{'mal_id': 55215, 'url': 'https://myanimelist.net/manga/55215/Utsuro_no_Hako_to_Zero_no_Maria', 'image_url': 'https://cdn.myanimelist.net/images/manga/2/175662.jpg?s=b9b22bf0e733997a1325b6461032eeac', 'title': 'Utsuro no Hako to Zero no Maria', 'publishing': False, 'synopsis': 'Kazuki Hoshino values his everyday life above all else. He spends the days carefree with his friends at school, until the uneventful bliss suddenly comes to a halt with the transfer of the aloof beaut...', 'type': 'Novel', 'chapters': 40, 'volumes': 7, 'score': 8.9, 'start_date': '2009-01-10T00:00:00+00:00', 'end_date': '2015-06-10T00:00:00+00:00', 'members': 67838}
>>> j.search("manga", "Hako to Zero", parameters={'type': 'novel', 'genre': 45})
{'request_hash': 'request:search:822526d692447538103d8049df898f648d350872', 'request_cached': True, 'request_cache_expiry': 41368, 'results': [], 'last_page': 1}

Corresponding MAL urls:

/v3/search/manga?q=Hako%20to%20Zero&type=novel&genre=1&
/v3/search/manga?q=Hako%20to%20Zero&type=novel&genre=45&

You can see the manga genre constants defined in the jikan here.

Place where this is defined in jikanpy

Thriller genre on MAL: https://myanimelist.net/manga/genre/45/Thriller

This could be fixed by changing the genre range depending on search_type, or having different key names for anime/manga genres (e.g. {'anime_genre': 43}, {'manga_genre': 45}), the former seems more reasonable.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.