Giter Club home page Giter Club logo

aiopokeapi's Introduction

class Me:
    def __init__(self) -> None:
        self.name = "beastmatser"
        self.programming_languages = [
            "python",
            "javascript"
        ]
        
    def reach(self) -> str:
        return "Discord: beastmatser#0728"

Beastmatser's GitHub stats

Top Langs

aiopokeapi's People

Contributors

beastmatser avatar deleca7755 avatar dependabot[bot] avatar joennespreuwers avatar padilin 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

Watchers

 avatar  avatar

aiopokeapi's Issues

Fetching a PokemonSpecies without a Habitat fails

Describe the bug
I am attempting to fetch a random PokemonSpecies from the National Pokedex. Due to incomplete data on PokeAPI, some fields are None. However, the package does not properly account for this. In this example, the habitat is None. This is the case for Pokemon starting in gen 4.

Traceback (most recent call last):
  File "c:\Users\---\PycharmProjects\PikalaxBOT\venv\Lib\site-packages\discord\app_commands\commands.py", line 842, in _do_call
    return await self._callback(interaction, **params)  # type: ignore
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\---\PycharmProjects\PikalaxBOT\pikalaxbot\ext\hangman.py", line 88, in hangman
    solution = await random.choice(natdex.pokemon_entries).pokemon_species.fetch()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\---\PycharmProjects\PikalaxBOT\venv\Lib\site-packages\aiopoke\utils\minimal_resources.py", line 103, in fetch
    obj: T = await build_map[self.endpoint](self.id)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\---\PycharmProjects\PikalaxBOT\venv\Lib\site-packages\aiopoke\utils\cache.py", line 27, in wrapper
    obj: U = await coro(client, name_or_id)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\---\PycharmProjects\PikalaxBOT\venv\Lib\site-packages\aiopoke\aiopoke_client.py", line 260, in get_pokemon_species
    return PokemonSpecies(**data)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\---\PycharmProjects\PikalaxBOT\venv\Lib\site-packages\aiopoke\objects\resources\pokemon\pokemon_species.py", line 105, in __init__
    self.habitat = MinimalResource(**habitat)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: aiopoke.utils.minimal_resources.MinimalResource() argument after ** must be a mapping, not NoneType

To Reproduce
Steps to reproduce the behavior:

  • Fetch a PokemonSpecies with ID 387 or higher

Expected behavior
A clear and concise description of what you expected to happen.
The PokemonSpecies is returned

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS] Windows 11
  • Browser [e.g. chrome, safari] N/A
  • Version [e.g. 22] 0.1.4-pypi on Python 3.11.1

Additional context
Add any other context about the problem here.

Cannot import `aiopoke` module

Module import fails even after installing by running pip install aiopokeapi. I have even tried using Python venv, but it still does not work.

To Reproduce

  1. Run pip install aiopokeapi
  2. In Python shell, run import aiopoke

Expected behavior
Module must be imported.

Screenshots
image

Desktop:

  • OS: Arch Linux
  • Python: 3.10.5

Possible bug: "TypeError: aiopoke.objects.resources.moves.move.ContestComboSets() argument after ** must be a mapping, not NoneType"

Describe the bug
I try to iterate through a bunch of move id's which are keys stored in a dict (map). Then I use moveData = await client.get_move(move) to get the move's data and to print the move's power. My program only iterates through the dict once, displays the move's id and power, but it crashes the second time with an error.

To Reproduce
Steps to reproduce the behavior:

  1. Store a pokemon's move id and name in a dictionary
  2. Iterate through the dictionary and use the keys to search for a move's data using get_move(move_id)
  3. See error
> Traceback (most recent call last):
>   File "/home/adrian/projects/poketype/prototype/old-main-aiopoke.py", line 121, in <module>
>     asyncio.run(main())
>   File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
>     return loop.run_until_complete(main)
>   File "/usr/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete
>     return future.result()
>   File "/home/adrian/projects/poketype/prototype/old-main-aiopoke.py", line 92, in main
>     await loadBaseDamage(opponentOne, opponentOneMoves)
>   File "/home/adrian/projects/poketype/prototype/old-main-aiopoke.py", line 65, in loadBaseDamage
>     moveData = await client.get_move(move)
>   File "/home/adrian/projects/virtualEnvironments/pokeTypeVenv/lib/python3.10/site-packages/aiopoke/utils/cache.py", line 27, in wrapper
>     obj: U = await coro(client, name_or_id)
>   File "/home/adrian/projects/virtualEnvironments/pokeTypeVenv/lib/python3.10/site-packages/aiopoke/aiopoke_client.py", line 193, in get_move
>     return Move(**data)
>   File "/home/adrian/projects/virtualEnvironments/pokeTypeVenv/lib/python3.10/site-packages/aiopoke/objects/resources/moves/move.py", line 87, in __init__
>     self.contest_combos = ContestComboSets(**contest_combos)
> TypeError: aiopoke.objects.resources.moves.move.ContestComboSets() argument after ** must be a mapping, not NoneType

Expected behavior
It's expected to retrieve the move's data, display the power, then repeat until the end of the dict is reached.

Desktop (please complete the following information):

  • OS: Windows 11

Additional context
Here is the file from the repository with the project I'm working on. The problem is in the loadBaseDamage() function, lines 61 - 66.

I'm not sure what type of bug this is, but this is all I know about this error.

'move_damage_class' field in 'type' should be set to nullable

Describe the bug
The 'move_damage_class' field in the response of https://pokeapi.co/api/v2/type/18 is null.
Run get_type(18) will produce an error like this:

Traceback (most recent call last):
  File "/home/zarkli/projects/python/test/./main.py", line 18, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/zarkli/projects/python/test/./main.py", line 12, in main
    type = await client.get_type(18)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/zarkli/.local/lib/python3.11/site-packages/aiopoke/utils/cache.py", line 27, in wrapper
    obj: U = await coro(client, name_or_id)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/zarkli/.local/lib/python3.11/site-packages/aiopoke/aiopoke_client.py", line 276, in get_type
    return NaturalGiftType(**data)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/zarkli/.local/lib/python3.11/site-packages/aiopoke/objects/resources/pokemon/natural_gift_type.py", line 42, in __init__
    self.move_damage_class = MinimalResource(**move_damage_class)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: aiopoke.utils.minimal_resources.MinimalResource() argument after ** must be a mapping, not NoneType

Edit: Don't know whether it is an error of the API itself (i.e. the move_damage_class should never be null. Sorry

TypeError with Move data - Must be mapping not nulltype

Describe the bug
I get a TypeError when after using using move_data = await client.get_move(int(move)) iteratively 9 times.

Expected behavior
Expected to iterate through a list of n ids and retrieve the move data from aiopokeapi client from an id from a list of ids.

To Reproduce
Steps to reproduce the behavior:

  1. Construct of list of move ids
  2. Inside a function, use async with aiopoke.AiopokeClient() as client:,
  3. Then, iterate the list of ids and populate a dict in this format: [id] = move_name, where the move_name is received from the aiopokeapi (i.e. move = client.get_move(id), then move_name = move.name).

Here is the code that caused the issue:

async def __load_moves(self, pokemon: Pokemon, pokemon_data):
    async with aiopoke.AiopokeClient() as client:
        moves_id = self.__get_move_ids(pokemon_data) # get the move ids first (returns a list)
        print(moves_id)
        # Use client to load the pokemon with its corresponding move_name, move_id, and move_power | Load it in the Pokemon type data member: moves = {}
        for move in moves_id:
            move_data = await client.get_move(int(move)) # Error on line 21
            new_move =  Move() # Imported Move class
            new_move.id = move
            new_move.name = move_data.name
            new_move.power = move_data.power
            new_move.type = move_data.type
            pokemon.moves[move_data.name] = new_move
            print(move_data.name)

Error Message

python3 pokeType_main.py < ../resources/input.txt > ../resources/output
  Traceback (most recent call last):
    File "/home/adrian/projects/poketype/prototype/main/pokeType_main.py", line 54, in <module>
      asyncio.run(main())
    File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
      return loop.run_until_complete(main)
    File "/usr/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
      return future.result()
    File "/home/adrian/projects/poketype/prototype/main/pokeType_main.py", line 42, in main
      await load_poke_data.load_pokemon(pokemon_1, pokemon_1_data)
    File "/home/adrian/projects/poketype/prototype/main/Load_Pokemon_Data.py", line 51, in load_pokemon
      await self.__load_moves(pokemon, pokemon_data)
    File "/home/adrian/projects/poketype/prototype/main/Load_Pokemon_Data.py", line 21, in __load_moves
      move_data = await client.get_move(int(move)) # API Wrapper Error on line 23
    File "/home/adrian/projects/virtualEnvironments/pokeTypeVenv/lib/python3.10/site-packages/aiopoke/utils/cache.py", line 27, in wrapper
      obj: U = await coro(client, name_or_id)
    File "/home/adrian/projects/virtualEnvironments/pokeTypeVenv/lib/python3.10/site-packages/aiopoke/aiopoke_client.py", line 200, in get_move
      return Move(**data)
    File "/home/adrian/projects/virtualEnvironments/pokeTypeVenv/lib/python3.10/site-packages/aiopoke/objects/resources/moves/move.py", line 114, in __init__
      self.past_values = [
    File "/home/adrian/projects/virtualEnvironments/pokeTypeVenv/lib/python3.10/site-packages/aiopoke/objects/resources/moves/move.py", line 115, in <listcomp>
      PastMoveStatValues(**past_value) for past_value in past_values
    File "/home/adrian/projects/virtualEnvironments/pokeTypeVenv/lib/python3.10/site-packages/aiopoke/objects/resources/moves/move.py", line 266, in __init__
      self.type = MinimalResource(**type)
  TypeError: aiopoke.utils.minimal_resources.MinimalResource() argument after ** must be a mapping, not NoneType

Desktop (please complete the following information):

  • OS: Windows 11
  • Python Version: 3.10.6
  • Aiopokeapi Version: 0.1.7

Additional context
I'm working on the same project I worked on before which can be found here. The specific file where this error occurred is here in line 21.

get_pokemon_species error with Gen 4+ Pokemon

Describe the bug
Traceback (most recent call last):
File "C:\Users\Me Too\Desktop\Scripts\Python\Discord\pbtest.py", line 42, in
asyncio.run(main())
File "C:\Users\Me Too\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py", line 190, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "C:\Users\Me Too\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Me Too\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 653, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "C:\Users\Me Too\Desktop\Scripts\Python\Discord\pbtest.py", line 6, in main
await client.get_pokemon_species(425)
File "C:\Users\Me Too\Desktop\Scripts\Python\Discord\venv\Lib\site-packages\aiopoke\utils\cache.py", line 27, in wrapper
obj: U = await coro(client, name_or_id)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Me Too\Desktop\Scripts\Python\Discord\venv\Lib\site-packages\aiopoke\aiopoke_client.py", line 260, in get_pokemon_species
return PokemonSpecies(**data)
^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Me Too\Desktop\Scripts\Python\Discord\venv\Lib\site-packages\aiopoke\objects\resources\pokemon\pokemon_species.py", line 105, in __init__
self.habitat = MinimalResource(**habitat)
^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: aiopoke.utils.minimal_resources.MinimalResource() argument after ** must be a mapping, not NoneType

Process finished with exit code 1


Habitats were only In the Pokédex In Gen 3, so It's null on anything after that and thus trying to get the species won't work

To Reproduce
Do await client.get_pokemon_species(<name or id of Gen 4+ Pokemon>)

Expected behavior
Gets the species without being stopped by the lack of a habitat

Screenshots
image

Desktop (please complete the following information)

  • OS: Windows 10
  • Browser: Firefox
  • Version: 22H2 19045.2604 (OS) 110.0 (Browser)

Some nullable values are not properly handled

Describe the bug
A TypeError happens when there's some resource on the PokéAPI that contains a null value that is not yet handled by aiopoke. An example could be anything that is Fairy-type because its move_damage_class is null.

To Reproduce
Steps to reproduce the behavior:

  1. Create a dummy Python script like this and run it:
    import asyncio
    from aiopoke import AiopokeClient
    
    async def get_type(name: str):
        async with AiopokeClient() as client:
            return await client.get_type(name)
    
    print(asyncio.run(get_type('fairy')))

Expected behavior
A NaturalGiftType object for the Fairy type should be printed.

Additional context
Specifications on which values should be nullable are in the schemas, for example, type.move_damage_class.

TypeError with Past Ability?

Describe the bug
I get a TypeError: PastAbility.__init__() got an unexpected keyword argument 'types' when using client.get_pokemon(pokemon) where I think any pokemon is from gen1 and had a type change (EX: Clefairy, Magneton, Marill).

Pokemon such as Pikachu, Bulbasaur, Fuecoco, etc. are not having this issue.

To Reproduce
Steps to reproduce the behavior:

  1. Construct a function to get pokemon info
  2. Use client = aiopoke.AiopokeClient()
  3. Call pokeInfo = await client.get_pokemon("clefairy")
  4. Get error

Here's a MWE of my code (in the context of a Discord bot):

async def getPoke(self, ctx:commands.Context, *args):
        client = aiopoke.AiopokeClient()
        pokeInfo = await client.get_pokemon("clefairy") #error happens here
        print(pokeInfo)

Expected behavior
Expected to get information on the input pokemon.

Error Message

Traceback (most recent call last):
  File "/Users/makaylamoster/Documents/QuelaBot/venv/lib/python3.11/site-packages/discord/ext/commands/core.py", line 235, in wrapped
    ret = await coro(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/makaylamoster/Documents/QuelaBot/cog_modules/pokemon/cog.py", line 111, in getPoke
    pokeInfo = await client.get_pokemon("clefairy")
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/makaylamoster/Documents/QuelaBot/venv/lib/python3.11/site-packages/aiopoke/utils/cache.py", line 27, in wrapper
    obj: U = await coro(client, name_or_id)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/makaylamoster/Documents/QuelaBot/venv/lib/python3.11/site-packages/aiopoke/aiopoke_client.py", line 253, in get_pokemon
    return Pokemon(**data)
           ^^^^^^^^^^^^^^^
  File "/Users/makaylamoster/Documents/QuelaBot/venv/lib/python3.11/site-packages/aiopoke/objects/resources/pokemon/pokemon.py", line 89, in __init__
    self.past_abilities = [PastAbility(**past_type) for past_type in past_types]
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/makaylamoster/Documents/QuelaBot/venv/lib/python3.11/site-packages/aiopoke/objects/resources/pokemon/pokemon.py", line 89, in <listcomp>
    self.past_abilities = [PastAbility(**past_type) for past_type in past_types]
                           ^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: PastAbility.__init__() got an unexpected keyword argument 'types'

Desktop (please complete the following information):

  • OS: macOS Vetura 13.5.2
  • Browser: Safari
  • Version: AioPoke v0.1.7
  • Python: 3.11.5

Additional context
It could just be me, but I'd appreciate any insights into fixing this error I'm getting.

Thanks so much!

File system caching (opt-in for now)

Is your feature request related to a problem? Please describe.
I'm making some sort of site with Pokémon data using Sanic that pulls PokéAPI data to generate pages, and your package was a good choice due to how well it composes with Sanic's preference for asynchronous request handlers.

Describe the solution you'd like
Unfortunately, because the default cache class does not interact with the file system in any way, the cache is always invalidated when the app closes. I would like for it to persist between app runs so people who visit the same page do not send another request against the PokéAPI, if there was any downtime in-between.

Describe alternatives you've considered
Both pokepy and pokebase have file system caching, but both of these packages are completely synchronous, which means the request can block the main loop, making my app unable to handle multiple requests in parallel.

Additional context
There should be a cache keyword argument to AiopokeClient.__init__, which should be set to the Cache class, or its instance.

Changes to AiopokeClient.__init__:

 class AiopokeClient(metaclass=MetaClient):
     http: HttpClient
-    _cache: Cache
+    cache: Cache
     
-    def __init__(self, *, session=None) -> None:
+    def __init__(self, *, session=None, cache=None) -> None:
         self.http = HttpClient(session=session)
-        self._cache = Cache()
+        if cache is None:
+            self.cache = Cache()
+        elif isinstance(cache, type):
+            self.cache = cache()
+        else:
+            self.cache = cache
         Url.link(self)
         Sprite.link(self)

Having the default for cache be None is to make sure we don't have mutable default arguments, which are considered bad practice.

An example implementation for a file system cache class could look like the one below. Shelves from the shelve standard library module can store arbitrary data types as values, but can only use strings as keys. However, it's still suitable for our purposes:

import shelve
import os


def _shelf_items(shelf):
    """
    Iterates through a shelve.Shelf's items.
    This is a workaround because the dict attribute of shelf objects
    does not have the .keys(), .values(), or .items() methods.
    """
    k = shelf.dict.firstkey()
    while k is not None:
        k = k.decode(shelf.keyencoding)
        yield (k, shelf[k])
        k = shelf.dict.nextkey(k)


class FileSystemCache:
    def __init__(self, filename="aiopoke_cache.dat"):
        if os.path.exists(filename):
            if not os.path.isfile(filename):
                raise ValueError(f"{filename!r} is not a file")
            # Do not open the file in write mode,
            # otherwise, the cache will be overridden
        else:
            # There is no 'as' keyword here because creating the file is
            # merely for side effects
            # Must use 'x' argument (create). If it were used with the
            # default, 'r', would error, saying the file does not exist
            with open(filename, "x"):
                pass
        self.filename = filename

    def get(self, id: Union[str, int]) -> Any:
        with shelve.open(self.filename) as shelf:
            return shelf.get(str(id))

    def put(self, id: Union[str, int], obj: Any) -> None:
        with shelve.open(self.filename, "w") as shelf:
            shelf[str(id)] = obj

    def has(self, obj: Any) -> bool:
        with shelve.open(self.filename) as shelf:
            for _, v in _shelf_items(shelf):
                if obj == v:
                    return True
        return False

Incorrect typehint for Nature.increased_stat, Nature.decreased_stat

In aiopoke.objects.resources.pokemon.nature.Nature, attributes increased_stat and decreased_stat are typehinted as Optional[MinimalResource["PokeathlonStat"]] when they should be Optional[MinimalResource["Stat"]]. This issue misleads linters into thinking the return type from await fetch() is PokeathlonStat rather than Stat.

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.