We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Keep heaviest pokemon
### Edited by moderator:

Submitting a request to have an option in the config to keep pokemon by their stats.
Example: Recycle pokemon by size.

---
#### Original Post:

Hi,

Is there a way to keep pokemons based on their weight or size instead of only iv or cp ?

Thanks


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pokemongo_bot/cell_workers/transfer_pokemon.py`
Content:
```
1 import json
2 import os
3 
4 from pokemongo_bot import inventory
5 from pokemongo_bot.human_behaviour import action_delay
6 from pokemongo_bot.base_task import BaseTask
7 from pokemongo_bot.inventory import Pokemons, Pokemon
8 
9 
10 class TransferPokemon(BaseTask):
11     SUPPORTED_TASK_API_VERSION = 1
12 
13     def initialize(self):
14         self.transfer_wait_min = self.config.get('transfer_wait_min', 1)
15         self.transfer_wait_max = self.config.get('transfer_wait_max', 4)
16 
17     def work(self):
18         pokemon_groups = self._release_pokemon_get_groups()
19         for pokemon_id, group in pokemon_groups.iteritems():
20             pokemon_name = Pokemons.name_for(pokemon_id)
21             keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name)
22 
23             if keep_best:
24                 best_pokemon_ids = set()
25                 order_criteria = 'none'
26                 if keep_best_cp >= 1:
27                     cp_limit = keep_best_cp
28                     best_cp_pokemons = sorted(group, key=lambda x: (x.cp, x.iv), reverse=True)[:cp_limit]
29                     best_pokemon_ids = set(pokemon.id for pokemon in best_cp_pokemons)
30                     order_criteria = 'cp'
31 
32                 if keep_best_iv >= 1:
33                     iv_limit = keep_best_iv
34                     best_iv_pokemons = sorted(group, key=lambda x: (x.iv, x.cp), reverse=True)[:iv_limit]
35                     best_pokemon_ids |= set(pokemon.id for pokemon in best_iv_pokemons)
36                     if order_criteria == 'cp':
37                         order_criteria = 'cp and iv'
38                     else:
39                         order_criteria = 'iv'
40 
41                 # remove best pokemons from all pokemons array
42                 all_pokemons = group
43                 best_pokemons = []
44                 for best_pokemon_id in best_pokemon_ids:
45                     for pokemon in all_pokemons:
46                         if best_pokemon_id == pokemon.id:
47                             all_pokemons.remove(pokemon)
48                             best_pokemons.append(pokemon)
49 
50                 transfer_pokemons = [pokemon for pokemon in all_pokemons if self.should_release_pokemon(pokemon,True)]
51 
52                 if transfer_pokemons:
53                     if best_pokemons:
54                         self.emit_event(
55                             'keep_best_release',
56                             formatted="Keeping best {amount} {pokemon}, based on {criteria}",
57                             data={
58                                 'amount': len(best_pokemons),
59                                 'pokemon': pokemon_name,
60                                 'criteria': order_criteria
61                             }
62                         )
63                     for pokemon in transfer_pokemons:
64                         self.release_pokemon(pokemon)
65             else:
66                 group = sorted(group, key=lambda x: x.cp, reverse=True)
67                 for pokemon in group:
68                     if self.should_release_pokemon(pokemon):
69                         self.release_pokemon(pokemon)
70 
71     def _release_pokemon_get_groups(self):
72         pokemon_groups = {}
73         # TODO: Use new inventory everywhere and then remove the inventory update
74         for pokemon in inventory.pokemons(True).all():
75             if pokemon.in_fort or pokemon.is_favorite:
76                 continue
77 
78             group_id = pokemon.pokemon_id
79 
80             if group_id not in pokemon_groups:
81                 pokemon_groups[group_id] = []
82 
83             pokemon_groups[group_id].append(pokemon)
84 
85         return pokemon_groups
86 
87     def should_release_pokemon(self, pokemon, keep_best_mode = False):
88         release_config = self._get_release_config_for(pokemon.name)
89 
90         if (keep_best_mode
91             and not release_config.has_key('never_release')
92             and not release_config.has_key('always_release')
93             and not release_config.has_key('release_below_cp')
94             and not release_config.has_key('release_below_iv')):
95             return True
96 
97         cp_iv_logic = release_config.get('logic')
98         if not cp_iv_logic:
99             cp_iv_logic = self._get_release_config_for('any').get('logic', 'and')
100 
101         release_results = {
102             'cp': False,
103             'iv': False,
104         }
105 
106         if release_config.get('never_release', False):
107             return False
108 
109         if release_config.get('always_release', False):
110             return True
111 
112         release_cp = release_config.get('release_below_cp', 0)
113         if pokemon.cp < release_cp:
114             release_results['cp'] = True
115 
116         release_iv = release_config.get('release_below_iv', 0)
117         if pokemon.iv < release_iv:
118             release_results['iv'] = True
119 
120         logic_to_function = {
121             'or': lambda x, y: x or y,
122             'and': lambda x, y: x and y
123         }
124 
125         if logic_to_function[cp_iv_logic](*release_results.values()):
126             self.emit_event(
127                 'future_pokemon_release',
128                 formatted="Releasing {pokemon} [CP {cp}] [IV {iv}] based on rule: CP < {below_cp} {cp_iv_logic} IV < {below_iv}",
129                 data={
130                     'pokemon': pokemon.name,
131                     'cp': pokemon.cp,
132                     'iv': pokemon.iv,
133                     'below_cp': release_cp,
134                     'cp_iv_logic': cp_iv_logic.upper(),
135                     'below_iv': release_iv
136                 }
137             )
138 
139         return logic_to_function[cp_iv_logic](*release_results.values())
140 
141     def release_pokemon(self, pokemon):
142         """
143 
144         :type pokemon: Pokemon
145         """
146         try:
147             if self.bot.config.test:
148                 candy_awarded = 1
149             else:
150                 response_dict = self.bot.api.release_pokemon(pokemon_id=pokemon.id)
151                 candy_awarded = response_dict['responses']['RELEASE_POKEMON']['candy_awarded']
152         except KeyError:
153             return
154 
155         # We could refresh here too, but adding 1 saves a inventory request
156         candy = inventory.candies().get(pokemon.pokemon_id)
157         candy.add(candy_awarded)
158         inventory.pokemons().remove(pokemon.id)
159         self.bot.metrics.released_pokemon()
160         self.emit_event(
161             'pokemon_release',
162             formatted='Exchanged {pokemon} [CP {cp}] [IV {iv}] for candy.',
163             data={
164                 'pokemon': pokemon.name,
165                 'cp': pokemon.cp,
166                 'iv': pokemon.iv,
167                 'ncp': pokemon.cp_percent,
168                 'dps': pokemon.moveset.dps
169             }
170         )
171         action_delay(self.transfer_wait_min, self.transfer_wait_max)
172 
173     def _get_release_config_for(self, pokemon):
174         release_config = self.bot.config.release.get(pokemon)
175         if not release_config:
176             release_config = self.bot.config.release.get('any')
177         if not release_config:
178             release_config = {}
179         return release_config
180 
181     def _validate_keep_best_config(self, pokemon_name):
182         keep_best = False
183 
184         release_config = self._get_release_config_for(pokemon_name)
185 
186         keep_best_cp = release_config.get('keep_best_cp', 0)
187         keep_best_iv = release_config.get('keep_best_iv', 0)
188 
189         if keep_best_cp or keep_best_iv:
190             keep_best = True
191             try:
192                 keep_best_cp = int(keep_best_cp)
193             except ValueError:
194                 keep_best_cp = 0
195 
196             try:
197                 keep_best_iv = int(keep_best_iv)
198             except ValueError:
199                 keep_best_iv = 0
200 
201             if keep_best_cp < 0 or keep_best_iv < 0:
202                 keep_best = False
203 
204             if keep_best_cp == 0 and keep_best_iv == 0:
205                 keep_best = False
206 
207         return keep_best, keep_best_cp, keep_best_iv
208
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pokemongo_bot/cell_workers/transfer_pokemon.py b/pokemongo_bot/cell_workers/transfer_pokemon.py
--- a/pokemongo_bot/cell_workers/transfer_pokemon.py
+++ b/pokemongo_bot/cell_workers/transfer_pokemon.py
@@ -4,8 +4,7 @@
 from pokemongo_bot import inventory
 from pokemongo_bot.human_behaviour import action_delay
 from pokemongo_bot.base_task import BaseTask
-from pokemongo_bot.inventory import Pokemons, Pokemon
-
+from pokemongo_bot.inventory import Pokemons, Pokemon, Attack
 
 class TransferPokemon(BaseTask):
     SUPPORTED_TASK_API_VERSION = 1
@@ -19,10 +18,13 @@
         for pokemon_id, group in pokemon_groups.iteritems():
             pokemon_name = Pokemons.name_for(pokemon_id)
             keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name)
-
+            #TODO continue list possible criteria
+            keep_best_possible_criteria = ['cp','iv', 'iv_attack', 'iv_defense', 'iv_stamina', 'moveset.attack_perfection','moveset.defense_perfection','hp','hp_max']
+            keep_best_custom, keep_best_criteria, keep_amount = self._validate_keep_best_config_custom(pokemon_name, keep_best_possible_criteria)
+            
+            best_pokemon_ids = set()
+            order_criteria = 'none'
             if keep_best:
-                best_pokemon_ids = set()
-                order_criteria = 'none'
                 if keep_best_cp >= 1:
                     cp_limit = keep_best_cp
                     best_cp_pokemons = sorted(group, key=lambda x: (x.cp, x.iv), reverse=True)[:cp_limit]
@@ -36,8 +38,14 @@
                     if order_criteria == 'cp':
                         order_criteria = 'cp and iv'
                     else:
-                        order_criteria = 'iv'
-
+                        order_criteria = 'iv'      
+            elif keep_best_custom:
+                limit = keep_amount
+                best_pokemons = sorted(group, key=lambda x: keep_best_criteria, reverse=True)[:limit]
+                best_pokemon_ids = set(pokemon.id for pokemon in best_pokemons)
+                order_criteria = ' and '.join(keep_best_criteria)
+                
+            if keep_best or keep_best_custom:
                 # remove best pokemons from all pokemons array
                 all_pokemons = group
                 best_pokemons = []
@@ -76,7 +84,7 @@
                 continue
 
             group_id = pokemon.pokemon_id
-
+            
             if group_id not in pokemon_groups:
                 pokemon_groups[group_id] = []
 
@@ -178,6 +186,32 @@
             release_config = {}
         return release_config
 
+    def _validate_keep_best_config_custom(self, pokemon_name, keep_best_possible_custom):
+        keep_best = False
+
+        release_config = self._get_release_config_for(pokemon_name)    
+        keep_best_custom = release_config.get('keep_best_custom', '')
+        keep_amount = release_config.get('amount', 0)
+
+        if keep_best_custom and keep_amount:
+            keep_best = True
+            
+            keep_best_custom = keep_best_custom.split(',')
+            for _str in keep_best_custom:
+                if _str not in keep_best_possible_custom:
+                    keep_best = False
+                    break
+
+            try:
+                keep_amount = int(keep_amount)
+            except ValueError:
+                keep_best = False
+              
+            if keep_amount < 0:
+                keep_best = False
+                
+        return keep_best, keep_best_custom, keep_amount
+        
     def _validate_keep_best_config(self, pokemon_name):
         keep_best = False
 
@@ -185,7 +219,7 @@
 
         keep_best_cp = release_config.get('keep_best_cp', 0)
         keep_best_iv = release_config.get('keep_best_iv', 0)
-
+        
         if keep_best_cp or keep_best_iv:
             keep_best = True
             try:
@@ -197,7 +231,7 @@
                 keep_best_iv = int(keep_best_iv)
             except ValueError:
                 keep_best_iv = 0
-
+                
             if keep_best_cp < 0 or keep_best_iv < 0:
                 keep_best = False

{"golden_diff": "diff --git a/pokemongo_bot/cell_workers/transfer_pokemon.py b/pokemongo_bot/cell_workers/transfer_pokemon.py\n--- a/pokemongo_bot/cell_workers/transfer_pokemon.py\n+++ b/pokemongo_bot/cell_workers/transfer_pokemon.py\n@@ -4,8 +4,7 @@\n from pokemongo_bot import inventory\n from pokemongo_bot.human_behaviour import action_delay\n from pokemongo_bot.base_task import BaseTask\n-from pokemongo_bot.inventory import Pokemons, Pokemon\n-\n+from pokemongo_bot.inventory import Pokemons, Pokemon, Attack\n \n class TransferPokemon(BaseTask):\n     SUPPORTED_TASK_API_VERSION = 1\n@@ -19,10 +18,13 @@\n         for pokemon_id, group in pokemon_groups.iteritems():\n             pokemon_name = Pokemons.name_for(pokemon_id)\n             keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name)\n-\n+            #TODO continue list possible criteria\n+            keep_best_possible_criteria = ['cp','iv', 'iv_attack', 'iv_defense', 'iv_stamina', 'moveset.attack_perfection','moveset.defense_perfection','hp','hp_max']\n+            keep_best_custom, keep_best_criteria, keep_amount = self._validate_keep_best_config_custom(pokemon_name, keep_best_possible_criteria)\n+            \n+            best_pokemon_ids = set()\n+            order_criteria = 'none'\n             if keep_best:\n-                best_pokemon_ids = set()\n-                order_criteria = 'none'\n                 if keep_best_cp >= 1:\n                     cp_limit = keep_best_cp\n                     best_cp_pokemons = sorted(group, key=lambda x: (x.cp, x.iv), reverse=True)[:cp_limit]\n@@ -36,8 +38,14 @@\n                     if order_criteria == 'cp':\n                         order_criteria = 'cp and iv'\n                     else:\n-                        order_criteria = 'iv'\n-\n+                        order_criteria = 'iv'      \n+            elif keep_best_custom:\n+                limit = keep_amount\n+                best_pokemons = sorted(group, key=lambda x: keep_best_criteria, reverse=True)[:limit]\n+                best_pokemon_ids = set(pokemon.id for pokemon in best_pokemons)\n+                order_criteria = ' and '.join(keep_best_criteria)\n+                \n+            if keep_best or keep_best_custom:\n                 # remove best pokemons from all pokemons array\n                 all_pokemons = group\n                 best_pokemons = []\n@@ -76,7 +84,7 @@\n                 continue\n \n             group_id = pokemon.pokemon_id\n-\n+            \n             if group_id not in pokemon_groups:\n                 pokemon_groups[group_id] = []\n \n@@ -178,6 +186,32 @@\n             release_config = {}\n         return release_config\n \n+    def _validate_keep_best_config_custom(self, pokemon_name, keep_best_possible_custom):\n+        keep_best = False\n+\n+        release_config = self._get_release_config_for(pokemon_name)    \n+        keep_best_custom = release_config.get('keep_best_custom', '')\n+        keep_amount = release_config.get('amount', 0)\n+\n+        if keep_best_custom and keep_amount:\n+            keep_best = True\n+            \n+            keep_best_custom = keep_best_custom.split(',')\n+            for _str in keep_best_custom:\n+                if _str not in keep_best_possible_custom:\n+                    keep_best = False\n+                    break\n+\n+            try:\n+                keep_amount = int(keep_amount)\n+            except ValueError:\n+                keep_best = False\n+              \n+            if keep_amount < 0:\n+                keep_best = False\n+                \n+        return keep_best, keep_best_custom, keep_amount\n+        \n     def _validate_keep_best_config(self, pokemon_name):\n         keep_best = False\n \n@@ -185,7 +219,7 @@\n \n         keep_best_cp = release_config.get('keep_best_cp', 0)\n         keep_best_iv = release_config.get('keep_best_iv', 0)\n-\n+        \n         if keep_best_cp or keep_best_iv:\n             keep_best = True\n             try:\n@@ -197,7 +231,7 @@\n                 keep_best_iv = int(keep_best_iv)\n             except ValueError:\n                 keep_best_iv = 0\n-\n+                \n             if keep_best_cp < 0 or keep_best_iv < 0:\n                 keep_best = False\n", "issue": "Keep heaviest pokemon\n### Edited by moderator:\n\nSubmitting a request to have an option in the config to keep pokemon by their stats.\nExample: Recycle pokemon by size.\n\n---\n#### Original Post:\n\nHi,\n\nIs there a way to keep pokemons based on their weight or size instead of only iv or cp ?\n\nThanks\n\n", "before_files": [{"content": "import json\nimport os\n\nfrom pokemongo_bot import inventory\nfrom pokemongo_bot.human_behaviour import action_delay\nfrom pokemongo_bot.base_task import BaseTask\nfrom pokemongo_bot.inventory import Pokemons, Pokemon\n\n\nclass TransferPokemon(BaseTask):\n    SUPPORTED_TASK_API_VERSION = 1\n\n    def initialize(self):\n        self.transfer_wait_min = self.config.get('transfer_wait_min', 1)\n        self.transfer_wait_max = self.config.get('transfer_wait_max', 4)\n\n    def work(self):\n        pokemon_groups = self._release_pokemon_get_groups()\n        for pokemon_id, group in pokemon_groups.iteritems():\n            pokemon_name = Pokemons.name_for(pokemon_id)\n            keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name)\n\n            if keep_best:\n                best_pokemon_ids = set()\n                order_criteria = 'none'\n                if keep_best_cp >= 1:\n                    cp_limit = keep_best_cp\n                    best_cp_pokemons = sorted(group, key=lambda x: (x.cp, x.iv), reverse=True)[:cp_limit]\n                    best_pokemon_ids = set(pokemon.id for pokemon in best_cp_pokemons)\n                    order_criteria = 'cp'\n\n                if keep_best_iv >= 1:\n                    iv_limit = keep_best_iv\n                    best_iv_pokemons = sorted(group, key=lambda x: (x.iv, x.cp), reverse=True)[:iv_limit]\n                    best_pokemon_ids |= set(pokemon.id for pokemon in best_iv_pokemons)\n                    if order_criteria == 'cp':\n                        order_criteria = 'cp and iv'\n                    else:\n                        order_criteria = 'iv'\n\n                # remove best pokemons from all pokemons array\n                all_pokemons = group\n                best_pokemons = []\n                for best_pokemon_id in best_pokemon_ids:\n                    for pokemon in all_pokemons:\n                        if best_pokemon_id == pokemon.id:\n                            all_pokemons.remove(pokemon)\n                            best_pokemons.append(pokemon)\n\n                transfer_pokemons = [pokemon for pokemon in all_pokemons if self.should_release_pokemon(pokemon,True)]\n\n                if transfer_pokemons:\n                    if best_pokemons:\n                        self.emit_event(\n                            'keep_best_release',\n                            formatted=\"Keeping best {amount} {pokemon}, based on {criteria}\",\n                            data={\n                                'amount': len(best_pokemons),\n                                'pokemon': pokemon_name,\n                                'criteria': order_criteria\n                            }\n                        )\n                    for pokemon in transfer_pokemons:\n                        self.release_pokemon(pokemon)\n            else:\n                group = sorted(group, key=lambda x: x.cp, reverse=True)\n                for pokemon in group:\n                    if self.should_release_pokemon(pokemon):\n                        self.release_pokemon(pokemon)\n\n    def _release_pokemon_get_groups(self):\n        pokemon_groups = {}\n        # TODO: Use new inventory everywhere and then remove the inventory update\n        for pokemon in inventory.pokemons(True).all():\n            if pokemon.in_fort or pokemon.is_favorite:\n                continue\n\n            group_id = pokemon.pokemon_id\n\n            if group_id not in pokemon_groups:\n                pokemon_groups[group_id] = []\n\n            pokemon_groups[group_id].append(pokemon)\n\n        return pokemon_groups\n\n    def should_release_pokemon(self, pokemon, keep_best_mode = False):\n        release_config = self._get_release_config_for(pokemon.name)\n\n        if (keep_best_mode\n            and not release_config.has_key('never_release')\n            and not release_config.has_key('always_release')\n            and not release_config.has_key('release_below_cp')\n            and not release_config.has_key('release_below_iv')):\n            return True\n\n        cp_iv_logic = release_config.get('logic')\n        if not cp_iv_logic:\n            cp_iv_logic = self._get_release_config_for('any').get('logic', 'and')\n\n        release_results = {\n            'cp': False,\n            'iv': False,\n        }\n\n        if release_config.get('never_release', False):\n            return False\n\n        if release_config.get('always_release', False):\n            return True\n\n        release_cp = release_config.get('release_below_cp', 0)\n        if pokemon.cp < release_cp:\n            release_results['cp'] = True\n\n        release_iv = release_config.get('release_below_iv', 0)\n        if pokemon.iv < release_iv:\n            release_results['iv'] = True\n\n        logic_to_function = {\n            'or': lambda x, y: x or y,\n            'and': lambda x, y: x and y\n        }\n\n        if logic_to_function[cp_iv_logic](*release_results.values()):\n            self.emit_event(\n                'future_pokemon_release',\n                formatted=\"Releasing {pokemon} [CP {cp}] [IV {iv}] based on rule: CP < {below_cp} {cp_iv_logic} IV < {below_iv}\",\n                data={\n                    'pokemon': pokemon.name,\n                    'cp': pokemon.cp,\n                    'iv': pokemon.iv,\n                    'below_cp': release_cp,\n                    'cp_iv_logic': cp_iv_logic.upper(),\n                    'below_iv': release_iv\n                }\n            )\n\n        return logic_to_function[cp_iv_logic](*release_results.values())\n\n    def release_pokemon(self, pokemon):\n        \"\"\"\n\n        :type pokemon: Pokemon\n        \"\"\"\n        try:\n            if self.bot.config.test:\n                candy_awarded = 1\n            else:\n                response_dict = self.bot.api.release_pokemon(pokemon_id=pokemon.id)\n                candy_awarded = response_dict['responses']['RELEASE_POKEMON']['candy_awarded']\n        except KeyError:\n            return\n\n        # We could refresh here too, but adding 1 saves a inventory request\n        candy = inventory.candies().get(pokemon.pokemon_id)\n        candy.add(candy_awarded)\n        inventory.pokemons().remove(pokemon.id)\n        self.bot.metrics.released_pokemon()\n        self.emit_event(\n            'pokemon_release',\n            formatted='Exchanged {pokemon} [CP {cp}] [IV {iv}] for candy.',\n            data={\n                'pokemon': pokemon.name,\n                'cp': pokemon.cp,\n                'iv': pokemon.iv,\n                'ncp': pokemon.cp_percent,\n                'dps': pokemon.moveset.dps\n            }\n        )\n        action_delay(self.transfer_wait_min, self.transfer_wait_max)\n\n    def _get_release_config_for(self, pokemon):\n        release_config = self.bot.config.release.get(pokemon)\n        if not release_config:\n            release_config = self.bot.config.release.get('any')\n        if not release_config:\n            release_config = {}\n        return release_config\n\n    def _validate_keep_best_config(self, pokemon_name):\n        keep_best = False\n\n        release_config = self._get_release_config_for(pokemon_name)\n\n        keep_best_cp = release_config.get('keep_best_cp', 0)\n        keep_best_iv = release_config.get('keep_best_iv', 0)\n\n        if keep_best_cp or keep_best_iv:\n            keep_best = True\n            try:\n                keep_best_cp = int(keep_best_cp)\n            except ValueError:\n                keep_best_cp = 0\n\n            try:\n                keep_best_iv = int(keep_best_iv)\n            except ValueError:\n                keep_best_iv = 0\n\n            if keep_best_cp < 0 or keep_best_iv < 0:\n                keep_best = False\n\n            if keep_best_cp == 0 and keep_best_iv == 0:\n                keep_best = False\n\n        return keep_best, keep_best_cp, keep_best_iv\n", "path": "pokemongo_bot/cell_workers/transfer_pokemon.py"}], "after_files": [{"content": "import json\nimport os\n\nfrom pokemongo_bot import inventory\nfrom pokemongo_bot.human_behaviour import action_delay\nfrom pokemongo_bot.base_task import BaseTask\nfrom pokemongo_bot.inventory import Pokemons, Pokemon, Attack\n\nclass TransferPokemon(BaseTask):\n    SUPPORTED_TASK_API_VERSION = 1\n\n    def initialize(self):\n        self.transfer_wait_min = self.config.get('transfer_wait_min', 1)\n        self.transfer_wait_max = self.config.get('transfer_wait_max', 4)\n\n    def work(self):\n        pokemon_groups = self._release_pokemon_get_groups()\n        for pokemon_id, group in pokemon_groups.iteritems():\n            pokemon_name = Pokemons.name_for(pokemon_id)\n            keep_best, keep_best_cp, keep_best_iv = self._validate_keep_best_config(pokemon_name)\n            #TODO continue list possible criteria\n            keep_best_possible_criteria = ['cp','iv', 'iv_attack', 'iv_defense', 'iv_stamina', 'moveset.attack_perfection','moveset.defense_perfection','hp','hp_max']\n            keep_best_custom, keep_best_criteria, keep_amount = self._validate_keep_best_config_custom(pokemon_name, keep_best_possible_criteria)\n            \n            best_pokemon_ids = set()\n            order_criteria = 'none'\n            if keep_best:\n                if keep_best_cp >= 1:\n                    cp_limit = keep_best_cp\n                    best_cp_pokemons = sorted(group, key=lambda x: (x.cp, x.iv), reverse=True)[:cp_limit]\n                    best_pokemon_ids = set(pokemon.id for pokemon in best_cp_pokemons)\n                    order_criteria = 'cp'\n\n                if keep_best_iv >= 1:\n                    iv_limit = keep_best_iv\n                    best_iv_pokemons = sorted(group, key=lambda x: (x.iv, x.cp), reverse=True)[:iv_limit]\n                    best_pokemon_ids |= set(pokemon.id for pokemon in best_iv_pokemons)\n                    if order_criteria == 'cp':\n                        order_criteria = 'cp and iv'\n                    else:\n                        order_criteria = 'iv'      \n            elif keep_best_custom:\n                limit = keep_amount\n                best_pokemons = sorted(group, key=lambda x: keep_best_criteria, reverse=True)[:limit]\n                best_pokemon_ids = set(pokemon.id for pokemon in best_pokemons)\n                order_criteria = ' and '.join(keep_best_criteria)\n                \n            if keep_best or keep_best_custom:\n                # remove best pokemons from all pokemons array\n                all_pokemons = group\n                best_pokemons = []\n                for best_pokemon_id in best_pokemon_ids:\n                    for pokemon in all_pokemons:\n                        if best_pokemon_id == pokemon.id:\n                            all_pokemons.remove(pokemon)\n                            best_pokemons.append(pokemon)\n\n                transfer_pokemons = [pokemon for pokemon in all_pokemons if self.should_release_pokemon(pokemon,True)]\n\n                if transfer_pokemons:\n                    if best_pokemons:\n                        self.emit_event(\n                            'keep_best_release',\n                            formatted=\"Keeping best {amount} {pokemon}, based on {criteria}\",\n                            data={\n                                'amount': len(best_pokemons),\n                                'pokemon': pokemon_name,\n                                'criteria': order_criteria\n                            }\n                        )\n                    for pokemon in transfer_pokemons:\n                        self.release_pokemon(pokemon)\n            else:\n                group = sorted(group, key=lambda x: x.cp, reverse=True)\n                for pokemon in group:\n                    if self.should_release_pokemon(pokemon):\n                        self.release_pokemon(pokemon)\n\n    def _release_pokemon_get_groups(self):\n        pokemon_groups = {}\n        # TODO: Use new inventory everywhere and then remove the inventory update\n        for pokemon in inventory.pokemons(True).all():\n            if pokemon.in_fort or pokemon.is_favorite:\n                continue\n\n            group_id = pokemon.pokemon_id\n            \n            if group_id not in pokemon_groups:\n                pokemon_groups[group_id] = []\n\n            pokemon_groups[group_id].append(pokemon)\n\n        return pokemon_groups\n\n    def should_release_pokemon(self, pokemon, keep_best_mode = False):\n        release_config = self._get_release_config_for(pokemon.name)\n\n        if (keep_best_mode\n            and not release_config.has_key('never_release')\n            and not release_config.has_key('always_release')\n            and not release_config.has_key('release_below_cp')\n            and not release_config.has_key('release_below_iv')):\n            return True\n\n        cp_iv_logic = release_config.get('logic')\n        if not cp_iv_logic:\n            cp_iv_logic = self._get_release_config_for('any').get('logic', 'and')\n\n        release_results = {\n            'cp': False,\n            'iv': False,\n        }\n\n        if release_config.get('never_release', False):\n            return False\n\n        if release_config.get('always_release', False):\n            return True\n\n        release_cp = release_config.get('release_below_cp', 0)\n        if pokemon.cp < release_cp:\n            release_results['cp'] = True\n\n        release_iv = release_config.get('release_below_iv', 0)\n        if pokemon.iv < release_iv:\n            release_results['iv'] = True\n\n        logic_to_function = {\n            'or': lambda x, y: x or y,\n            'and': lambda x, y: x and y\n        }\n\n        if logic_to_function[cp_iv_logic](*release_results.values()):\n            self.emit_event(\n                'future_pokemon_release',\n                formatted=\"Releasing {pokemon} [CP {cp}] [IV {iv}] based on rule: CP < {below_cp} {cp_iv_logic} IV < {below_iv}\",\n                data={\n                    'pokemon': pokemon.name,\n                    'cp': pokemon.cp,\n                    'iv': pokemon.iv,\n                    'below_cp': release_cp,\n                    'cp_iv_logic': cp_iv_logic.upper(),\n                    'below_iv': release_iv\n                }\n            )\n\n        return logic_to_function[cp_iv_logic](*release_results.values())\n\n    def release_pokemon(self, pokemon):\n        \"\"\"\n\n        :type pokemon: Pokemon\n        \"\"\"\n        try:\n            if self.bot.config.test:\n                candy_awarded = 1\n            else:\n                response_dict = self.bot.api.release_pokemon(pokemon_id=pokemon.id)\n                candy_awarded = response_dict['responses']['RELEASE_POKEMON']['candy_awarded']\n        except KeyError:\n            return\n\n        # We could refresh here too, but adding 1 saves a inventory request\n        candy = inventory.candies().get(pokemon.pokemon_id)\n        candy.add(candy_awarded)\n        inventory.pokemons().remove(pokemon.id)\n        self.bot.metrics.released_pokemon()\n        self.emit_event(\n            'pokemon_release',\n            formatted='Exchanged {pokemon} [CP {cp}] [IV {iv}] for candy.',\n            data={\n                'pokemon': pokemon.name,\n                'cp': pokemon.cp,\n                'iv': pokemon.iv,\n                'ncp': pokemon.cp_percent,\n                'dps': pokemon.moveset.dps\n            }\n        )\n        action_delay(self.transfer_wait_min, self.transfer_wait_max)\n\n    def _get_release_config_for(self, pokemon):\n        release_config = self.bot.config.release.get(pokemon)\n        if not release_config:\n            release_config = self.bot.config.release.get('any')\n        if not release_config:\n            release_config = {}\n        return release_config\n\n    def _validate_keep_best_config_custom(self, pokemon_name, keep_best_possible_custom):\n        keep_best = False\n\n        release_config = self._get_release_config_for(pokemon_name)    \n        keep_best_custom = release_config.get('keep_best_custom', '')\n        keep_amount = release_config.get('amount', 0)\n\n        if keep_best_custom and keep_amount:\n            keep_best = True\n            \n            keep_best_custom = keep_best_custom.split(',')\n            for _str in keep_best_custom:\n                if _str not in keep_best_possible_custom:\n                    keep_best = False\n                    break\n\n            try:\n                keep_amount = int(keep_amount)\n            except ValueError:\n                keep_best = False\n              \n            if keep_amount < 0:\n                keep_best = False\n                \n        return keep_best, keep_best_custom, keep_amount\n        \n    def _validate_keep_best_config(self, pokemon_name):\n        keep_best = False\n\n        release_config = self._get_release_config_for(pokemon_name)\n\n        keep_best_cp = release_config.get('keep_best_cp', 0)\n        keep_best_iv = release_config.get('keep_best_iv', 0)\n        \n        if keep_best_cp or keep_best_iv:\n            keep_best = True\n            try:\n                keep_best_cp = int(keep_best_cp)\n            except ValueError:\n                keep_best_cp = 0\n\n            try:\n                keep_best_iv = int(keep_best_iv)\n            except ValueError:\n                keep_best_iv = 0\n                \n            if keep_best_cp < 0 or keep_best_iv < 0:\n                keep_best = False\n\n            if keep_best_cp == 0 and keep_best_iv == 0:\n                keep_best = False\n\n        return keep_best, keep_best_cp, keep_best_iv\n", "path": "pokemongo_bot/cell_workers/transfer_pokemon.py"}]}