├── .circleci
└── config.yml
├── .gitignore
├── .pylintrc
├── LICENSE
├── Makefile
├── README.md
├── docs
├── authors.md
├── contributing.md
├── history.md
├── index.md
├── installation.md
├── stylesheets
│ └── extra.css
└── usage.md
├── make.bat
├── mkdocs.yml
├── pokepy
├── __init__.py
├── api.py
├── fcache
│ ├── __init__.py
│ ├── cache.py
│ └── posixemulation.py
└── resources_v2.py
├── requirements-dev.txt
├── requirements-dev27.txt
├── requirements.txt
├── setup.cfg
├── setup.py
├── tests
├── __init__.py
└── test_pokepy.py
└── tox.ini
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Config file for automatic testing at circleci.com
2 |
3 |
4 | version: 2.1
5 |
6 |
7 | orbs:
8 | windows: circleci/windows@2.4.0
9 |
10 |
11 | # -------------------------
12 | # COMMANDS
13 | # -------------------------
14 | commands:
15 |
16 | tests-only:
17 | steps:
18 | - checkout
19 | - run:
20 | name: Install Requirements
21 | command: pip install -r requirements.txt -r requirements-dev27.txt --user
22 | - run:
23 | name: Run Tests
24 | command: make test
25 |
26 | tests-coverage-lint:
27 | steps:
28 | - checkout
29 | - run:
30 | name: Install Requirements
31 | command: sudo pip install -r requirements.txt -r requirements-dev.txt
32 | - run:
33 | name: Lint
34 | command: make lint
35 | - run:
36 | name: Run Tests
37 | command: make test
38 | - run:
39 | name: Run Coverage tool
40 | command: coverage run --source pokepy --omit="pokepy/fcache/*" -m unittest tests.test_pokepy
41 | - run:
42 | name: Generate XML coverage report
43 | command: coverage xml
44 | - run:
45 | name: Upload Coverage report to CodeCov
46 | command: bash <(curl -s https://codecov.io/bash)
47 |
48 |
49 | # -------------------------
50 | # JOBS
51 | # -------------------------
52 | jobs:
53 |
54 | py27-linux:
55 | docker:
56 | - image: circleci/python:2.7.18
57 | steps:
58 | - tests-only
59 |
60 | py34-linux:
61 | docker:
62 | - image: circleci/python:3.4.10
63 | steps:
64 | - tests-only
65 |
66 | py35-linux:
67 | docker:
68 | - image: circleci/python:3.5.8
69 | steps:
70 | - tests-only
71 |
72 | py36-linux:
73 | docker:
74 | - image: circleci/python:3.6.10
75 | steps:
76 | - tests-only
77 |
78 | py37-linux:
79 | docker:
80 | - image: circleci/python:3.7.7
81 | steps:
82 | - tests-coverage-lint
83 |
84 | py38-linux:
85 | docker:
86 | - image: circleci/python:3.8.3
87 | steps:
88 | - tests-only
89 |
90 | py37-windows:
91 | executor:
92 | name: windows/default
93 | shell: cmd.exe
94 | steps:
95 | - tests-only
96 |
97 | py27-windows:
98 | executor:
99 | name: windows/default
100 | shell: cmd.exe
101 | steps:
102 | - checkout
103 | - run:
104 | name: Install Python 2.7
105 | command: choco install python2
106 | - run:
107 | name: Install Requirements
108 | command: C:\Python27\Scripts\pip.exe --version && C:\Python27\Scripts\pip.exe install -r requirements.txt -r requirements-dev27.txt --user
109 | - run:
110 | name: Run Tests
111 | command: C:\Python27\python.exe --version && C:\Python27\python.exe -m unittest tests.test_pokepy
112 |
113 |
114 | # -------------------------
115 | # WORKFLOW
116 | # -------------------------
117 | workflows:
118 | version: 2
119 | run_tests:
120 | jobs:
121 | - py27-linux
122 | - py34-linux
123 | - py35-linux
124 | - py36-linux
125 | - py37-linux
126 | - py38-linux
127 | - py37-windows
128 | - py27-windows
129 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.py[cod]
2 |
3 | # C extensions
4 | *.so
5 |
6 | # Packages
7 | *.egg*
8 | *.cache
9 | *.egg-info
10 | dist
11 | build
12 | eggs
13 | parts
14 | bin
15 | var
16 | sdist
17 | develop-eggs
18 | .installed.cfg
19 | lib
20 | lib64
21 |
22 | # Installer logs
23 | pip-log.txt
24 |
25 | # Unit test / coverage reports
26 | .coverage
27 | .tox
28 |
29 | # html_coverage
30 | html_coverage/
31 |
32 | # Pycharm
33 | .idea/
34 |
35 | # virtual environment
36 | venv/
37 |
38 | # Mkdocs build dir
39 | site/
40 |
41 | package-lock.json
42 | node_modules
--------------------------------------------------------------------------------
/.pylintrc:
--------------------------------------------------------------------------------
1 | [MASTER]
2 |
3 | # A comma-separated list of package or module names from where C extensions may
4 | # be loaded. Extensions are loading into the active Python interpreter and may
5 | # run arbitrary code.
6 | extension-pkg-whitelist=
7 |
8 | # Add files or directories to the blacklist. They should be base names, not
9 | # paths.
10 | ignore=docs
11 |
12 | # Add files or directories matching the regex patterns to the blacklist. The
13 | # regex matches against base names, not paths.
14 | ignore-patterns=
15 |
16 | # Python code to execute, usually for sys.path manipulation such as
17 | # pygtk.require().
18 | #init-hook=
19 |
20 | # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
21 | # number of processors available to use.
22 | jobs=0
23 |
24 | # Control the amount of potential inferred values when inferring a single
25 | # object. This can help the performance when dealing with large functions or
26 | # complex, nested conditions.
27 | limit-inference-results=100
28 |
29 | # List of plugins (as comma separated values of python modules names) to load,
30 | # usually to register additional checkers.
31 | load-plugins=
32 |
33 | # Pickle collected data for later comparisons.
34 | persistent=yes
35 |
36 | # Specify a configuration file.
37 | #rcfile=
38 |
39 | # When enabled, pylint would attempt to guess common misconfiguration and emit
40 | # user-friendly hints instead of false-positive error messages.
41 | suggestion-mode=yes
42 |
43 | # Allow loading of arbitrary C extensions. Extensions are imported into the
44 | # active Python interpreter and may run arbitrary code.
45 | unsafe-load-any-extension=no
46 |
47 |
48 | [MESSAGES CONTROL]
49 |
50 | # Only show warnings with the listed confidence levels. Leave empty to show
51 | # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
52 | confidence=
53 |
54 | # Disable the message, report, category or checker with the given id(s). You
55 | # can either give multiple identifiers separated by comma (,) or put this
56 | # option multiple times (only on the command line, not in the configuration
57 | # file where it should appear only once). You can also use "--disable=all" to
58 | # disable everything first and then reenable specific checks. For example, if
59 | # you want to run only the similarities checker, you can use "--disable=all
60 | # --enable=similarities". If you want to run only the classes checker, but have
61 | # no Warning level messages displayed, use "--disable=all --enable=classes
62 | # --disable=W".
63 | disable=missing-docstring,
64 | function-redefined,
65 | too-many-lines,
66 | no-member,
67 | keyword-arg-before-vararg,
68 | fixme,
69 | too-many-instance-attributes,
70 |
71 | # Disabled by default:
72 |
73 | print-statement,
74 | parameter-unpacking,
75 | unpacking-in-except,
76 | old-raise-syntax,
77 | backtick,
78 | long-suffix,
79 | old-ne-operator,
80 | old-octal-literal,
81 | import-star-module-level,
82 | non-ascii-bytes-literal,
83 | raw-checker-failed,
84 | bad-inline-option,
85 | locally-disabled,
86 | locally-enabled,
87 | file-ignored,
88 | suppressed-message,
89 | useless-suppression,
90 | deprecated-pragma,
91 | use-symbolic-message-instead,
92 | apply-builtin,
93 | basestring-builtin,
94 | buffer-builtin,
95 | cmp-builtin,
96 | coerce-builtin,
97 | execfile-builtin,
98 | file-builtin,
99 | long-builtin,
100 | raw_input-builtin,
101 | reduce-builtin,
102 | standarderror-builtin,
103 | unicode-builtin,
104 | xrange-builtin,
105 | coerce-method,
106 | delslice-method,
107 | getslice-method,
108 | setslice-method,
109 | no-absolute-import,
110 | old-division,
111 | dict-iter-method,
112 | dict-view-method,
113 | next-method-called,
114 | metaclass-assignment,
115 | indexing-exception,
116 | raising-string,
117 | reload-builtin,
118 | oct-method,
119 | hex-method,
120 | nonzero-method,
121 | cmp-method,
122 | input-builtin,
123 | round-builtin,
124 | intern-builtin,
125 | unichr-builtin,
126 | map-builtin-not-iterating,
127 | zip-builtin-not-iterating,
128 | range-builtin-not-iterating,
129 | filter-builtin-not-iterating,
130 | using-cmp-argument,
131 | eq-without-hash,
132 | div-method,
133 | idiv-method,
134 | rdiv-method,
135 | exception-message-attribute,
136 | invalid-str-codec,
137 | sys-max-int,
138 | bad-python3-import,
139 | deprecated-string-function,
140 | deprecated-str-translate-call,
141 | deprecated-itertools-function,
142 | deprecated-types-field,
143 | next-method-defined,
144 | dict-items-not-iterating,
145 | dict-keys-not-iterating,
146 | dict-values-not-iterating,
147 | deprecated-operator-function,
148 | deprecated-urllib-function,
149 | xreadlines-attribute,
150 | deprecated-sys-function,
151 | exception-escape,
152 | comprehension-escape
153 |
154 | # Enable the message, report, category or checker with the given id(s). You can
155 | # either give multiple identifier separated by comma (,) or put this option
156 | # multiple time (only on the command line, not in the configuration file where
157 | # it should appear only once). See also the "--disable" option for examples.
158 | enable=c-extension-no-member
159 |
160 |
161 | [REPORTS]
162 |
163 | # Python expression which should return a note less than 10 (10 is the highest
164 | # note). You have access to the variables errors warning, statement which
165 | # respectively contain the number of errors / warnings messages and the total
166 | # number of statements analyzed. This is used by the global evaluation report
167 | # (RP0004).
168 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
169 |
170 | # Template used to display messages. This is a python new-style format string
171 | # used to format the message information. See doc for all details.
172 | #msg-template=
173 |
174 | # Set the output format. Available formats are text, parseable, colorized, json
175 | # and msvs (visual studio). You can also give a reporter class, e.g.
176 | # mypackage.mymodule.MyReporterClass.
177 | output-format=text
178 |
179 | # Tells whether to display a full report or only the messages.
180 | reports=no
181 |
182 | # Activate the evaluation score.
183 | score=yes
184 |
185 |
186 | [REFACTORING]
187 |
188 | # Maximum number of nested blocks for function / method body
189 | max-nested-blocks=5
190 |
191 | # Complete name of functions that never returns. When checking for
192 | # inconsistent-return-statements if a never returning function is called then
193 | # it will be considered as an explicit return statement and no message will be
194 | # printed.
195 | never-returning-functions=sys.exit
196 |
197 |
198 | [BASIC]
199 |
200 | # Naming style matching correct argument names.
201 | argument-naming-style=snake_case
202 |
203 | # Regular expression matching correct argument names. Overrides argument-
204 | # naming-style.
205 | #argument-rgx=
206 |
207 | # Naming style matching correct attribute names.
208 | attr-naming-style=snake_case
209 |
210 | # Regular expression matching correct attribute names. Overrides attr-naming-
211 | # style.
212 | #attr-rgx=
213 |
214 | # Bad variable names which should always be refused, separated by a comma.
215 | bad-names=foo,
216 | bar,
217 | baz,
218 | toto,
219 | tutu,
220 | tata
221 |
222 | # Naming style matching correct class attribute names.
223 | class-attribute-naming-style=any
224 |
225 | # Regular expression matching correct class attribute names. Overrides class-
226 | # attribute-naming-style.
227 | #class-attribute-rgx=
228 |
229 | # Naming style matching correct class names.
230 | class-naming-style=PascalCase
231 |
232 | # Regular expression matching correct class names. Overrides class-naming-
233 | # style.
234 | #class-rgx=
235 |
236 | # Naming style matching correct constant names.
237 | const-naming-style=snake_case
238 |
239 | # Regular expression matching correct constant names. Overrides const-naming-
240 | # style.
241 | #const-rgx=
242 |
243 | # Minimum line length for functions/classes that require docstrings, shorter
244 | # ones are exempt.
245 | docstring-min-length=-1
246 |
247 | # Naming style matching correct function names.
248 | function-naming-style=snake_case
249 |
250 | # Regular expression matching correct function names. Overrides function-
251 | # naming-style.
252 | #function-rgx=
253 |
254 | # Good variable names which should always be accepted, separated by a comma.
255 | good-names=i,
256 | j,
257 | k,
258 | ex,
259 | Run,
260 | _
261 |
262 | # Include a hint for the correct naming format with invalid-name.
263 | include-naming-hint=yes
264 |
265 | # Naming style matching correct inline iteration names.
266 | inlinevar-naming-style=any
267 |
268 | # Regular expression matching correct inline iteration names. Overrides
269 | # inlinevar-naming-style.
270 | #inlinevar-rgx=
271 |
272 | # Naming style matching correct method names.
273 | method-naming-style=snake_case
274 |
275 | # Regular expression matching correct method names. Overrides method-naming-
276 | # style.
277 | #method-rgx=
278 |
279 | # Naming style matching correct module names.
280 | module-naming-style=snake_case
281 |
282 | # Regular expression matching correct module names. Overrides module-naming-
283 | # style.
284 | #module-rgx=
285 |
286 | # Colon-delimited sets of names that determine each other's naming style when
287 | # the name regexes allow several styles.
288 | name-group=
289 |
290 | # Regular expression which should only match function or class names that do
291 | # not require a docstring.
292 | no-docstring-rgx=^_
293 |
294 | # List of decorators that produce properties, such as abc.abstractproperty. Add
295 | # to this list to register other decorators that produce valid properties.
296 | # These decorators are taken in consideration only for invalid-name.
297 | property-classes=abc.abstractproperty
298 |
299 | # Naming style matching correct variable names.
300 | variable-naming-style=snake_case
301 |
302 | # Regular expression matching correct variable names. Overrides variable-
303 | # naming-style.
304 | variable-rgx=[a-z0-9_]{1,75}$
305 |
306 |
307 | [FORMAT]
308 |
309 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
310 | expected-line-ending-format=
311 |
312 | # Regexp for a line that is allowed to be longer than the limit.
313 | ignore-long-lines=^\s*(# )??$
314 |
315 | # Number of spaces of indent required inside a hanging or continued line.
316 | indent-after-paren=4
317 |
318 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
319 | # tab).
320 | indent-string=' '
321 |
322 | # Maximum number of characters on a single line.
323 | max-line-length=100
324 |
325 | # Maximum number of lines in a module.
326 | max-module-lines=1000
327 |
328 | # List of optional constructs for which whitespace checking is disabled. `dict-
329 | # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
330 | # `trailing-comma` allows a space between comma and closing bracket: (a, ).
331 | # `empty-line` allows space-only lines.
332 | no-space-check=trailing-comma,
333 | dict-separator
334 |
335 | # Allow the body of a class to be on the same line as the declaration if body
336 | # contains single statement.
337 | single-line-class-stmt=no
338 |
339 | # Allow the body of an if to be on the same line as the test if there is no
340 | # else.
341 | single-line-if-stmt=no
342 |
343 |
344 | [LOGGING]
345 |
346 | # Logging modules to check that the string format arguments are in logging
347 | # function parameter format.
348 | logging-modules=logging
349 |
350 |
351 | [MISCELLANEOUS]
352 |
353 | # List of note tags to take in consideration, separated by a comma.
354 | notes=FIXME,
355 | XXX,
356 | TODO
357 |
358 |
359 | [SIMILARITIES]
360 |
361 | # Ignore comments when computing similarities.
362 | ignore-comments=yes
363 |
364 | # Ignore docstrings when computing similarities.
365 | ignore-docstrings=yes
366 |
367 | # Ignore imports when computing similarities.
368 | ignore-imports=no
369 |
370 | # Minimum lines number of a similarity.
371 | min-similarity-lines=4
372 |
373 |
374 | [SPELLING]
375 |
376 | # Limits count of emitted suggestions for spelling mistakes.
377 | max-spelling-suggestions=4
378 |
379 | # Spelling dictionary name. Available dictionaries: none. To make it working
380 | # install python-enchant package..
381 | spelling-dict=
382 |
383 | # List of comma separated words that should not be checked.
384 | spelling-ignore-words=
385 |
386 | # A path to a file that contains private dictionary; one word per line.
387 | spelling-private-dict-file=
388 |
389 | # Tells whether to store unknown words to indicated private dictionary in
390 | # --spelling-private-dict-file option instead of raising a message.
391 | spelling-store-unknown-words=no
392 |
393 |
394 | [TYPECHECK]
395 |
396 | # List of decorators that produce context managers, such as
397 | # contextlib.contextmanager. Add to this list to register other decorators that
398 | # produce valid context managers.
399 | contextmanager-decorators=contextlib.contextmanager
400 |
401 | # List of members which are set dynamically and missed by pylint inference
402 | # system, and so shouldn't trigger E1101 when accessed. Python regular
403 | # expressions are accepted.
404 | generated-members=
405 |
406 | # Tells whether missing members accessed in mixin class should be ignored. A
407 | # mixin class is detected if its name ends with "mixin" (case insensitive).
408 | ignore-mixin-members=yes
409 |
410 | # Tells whether to warn about missing members when the owner of the attribute
411 | # is inferred to be None.
412 | ignore-none=yes
413 |
414 | # This flag controls whether pylint should warn about no-member and similar
415 | # checks whenever an opaque object is returned when inferring. The inference
416 | # can return multiple potential results while evaluating a Python object, but
417 | # some branches might not be evaluated, which results in partial inference. In
418 | # that case, it might be useful to still emit no-member and other checks for
419 | # the rest of the inferred objects.
420 | ignore-on-opaque-inference=yes
421 |
422 | # List of class names for which member attributes should not be checked (useful
423 | # for classes with dynamically set attributes). This supports the use of
424 | # qualified names.
425 | ignored-classes=optparse.Values,thread._local,_thread._local
426 |
427 | # List of module names for which member attributes should not be checked
428 | # (useful for modules/projects where namespaces are manipulated during runtime
429 | # and thus existing member attributes cannot be deduced by static analysis. It
430 | # supports qualified module names, as well as Unix pattern matching.
431 | ignored-modules=
432 |
433 | # Show a hint with possible names when a member name was not found. The aspect
434 | # of finding the hint is based on edit distance.
435 | missing-member-hint=yes
436 |
437 | # The minimum edit distance a name should have in order to be considered a
438 | # similar match for a missing member name.
439 | missing-member-hint-distance=1
440 |
441 | # The total number of similar names that should be taken in consideration when
442 | # showing a hint for a missing member.
443 | missing-member-max-choices=1
444 |
445 |
446 | [VARIABLES]
447 |
448 | # List of additional names supposed to be defined in builtins. Remember that
449 | # you should avoid to define new builtins when possible.
450 | additional-builtins=
451 |
452 | # Tells whether unused global variables should be treated as a violation.
453 | allow-global-unused-variables=yes
454 |
455 | # List of strings which can identify a callback function by name. A callback
456 | # name must start or end with one of those strings.
457 | callbacks=cb_,
458 | _cb
459 |
460 | # A regular expression matching the name of dummy variables (i.e. expected to
461 | # not be used).
462 | dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
463 |
464 | # Argument names that match this expression will be ignored. Default to name
465 | # with leading underscore.
466 | ignored-argument-names=_.*|^ignored_|^unused_
467 |
468 | # Tells whether we should check for unused import in __init__ files.
469 | init-import=no
470 |
471 | # List of qualified module names which can have objects that can redefine
472 | # builtins.
473 | redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
474 |
475 |
476 | [CLASSES]
477 |
478 | # List of method names used to declare (i.e. assign) instance attributes.
479 | defining-attr-methods=__init__,
480 | __new__,
481 | setUp
482 |
483 | # List of member names, which should be excluded from the protected access
484 | # warning.
485 | exclude-protected=_asdict,
486 | _fields,
487 | _replace,
488 | _source,
489 | _make
490 |
491 | # List of valid names for the first argument in a class method.
492 | valid-classmethod-first-arg=cls
493 |
494 | # List of valid names for the first argument in a metaclass class method.
495 | valid-metaclass-classmethod-first-arg=cls
496 |
497 |
498 | [DESIGN]
499 |
500 | # Maximum number of arguments for function / method.
501 | max-args=10 # default = 5
502 |
503 | # Maximum number of attributes for a class (see R0902).
504 | max-attributes=7
505 |
506 | # Maximum number of boolean expressions in an if statement.
507 | max-bool-expr=5
508 |
509 | # Maximum number of branch for function / method body.
510 | max-branches=12
511 |
512 | # Maximum number of locals for function / method body.
513 | max-locals=15
514 |
515 | # Maximum number of parents for a class (see R0901).
516 | max-parents=7
517 |
518 | # Maximum number of public methods for a class (see R0904).
519 | max-public-methods=500 # default = 20
520 |
521 | # Maximum number of return / yield for function / method body.
522 | max-returns=6
523 |
524 | # Maximum number of statements in function / method body.
525 | max-statements=50
526 |
527 | # Minimum number of public methods for a class (see R0903).
528 | min-public-methods=0 # default = 2
529 |
530 |
531 | [IMPORTS]
532 |
533 | # Allow wildcard imports from modules that define __all__.
534 | allow-wildcard-with-all=no
535 |
536 | # Analyse import fallback blocks. This can be used to support both Python 2 and
537 | # 3 compatible code, which means that the block might have code that exists
538 | # only in one or another interpreter, leading to false positives when analysed.
539 | analyse-fallback-blocks=no
540 |
541 | # Deprecated modules which should not be used, separated by a comma.
542 | deprecated-modules=optparse,tkinter.tix
543 |
544 | # Create a graph of external dependencies in the given file (report RP0402 must
545 | # not be disabled).
546 | ext-import-graph=
547 |
548 | # Create a graph of every (i.e. internal and external) dependencies in the
549 | # given file (report RP0402 must not be disabled).
550 | import-graph=
551 |
552 | # Create a graph of internal dependencies in the given file (report RP0402 must
553 | # not be disabled).
554 | int-import-graph=
555 |
556 | # Force import order to recognize a module as part of the standard
557 | # compatibility libraries.
558 | known-standard-library=
559 |
560 | # Force import order to recognize a module as part of a third party library.
561 | known-third-party=enchant
562 |
563 |
564 | [EXCEPTIONS]
565 |
566 | # Exceptions that will emit a warning when being caught. Defaults to
567 | # "Exception".
568 | overgeneral-exceptions=Exception
569 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016, Paul Hallett
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5 |
6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7 |
8 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9 |
10 | * Neither the name of Pokepy nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11 |
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: help clean clean-build clean-pyc clean-tests clean-docs lint test test-all coverage docs-build docs-test docs-release sdist sdist-test release
2 |
3 | help:
4 | @echo "clean removes build and python file artifacts"
5 | @echo "clean-build removes build artifacts"
6 | @echo "clean-pyc removes python file artifacts"
7 | @echo "clean-tests removes test and coverage files"
8 | @echo "clean-docs removes built docs files"
9 | @echo "lint checks style with pylint"
10 | @echo "test runs tests quickly with the default python version"
11 | @echo "test-all runs tests on every python version with tox"
12 | @echo "coverage checks code coverage quickly with the default python version"
13 | @echo "docs-build builds MkDocs HTML documentation"
14 | @echo "docs-test live tests the current documentation"
15 | @echo "docs-release pushes built docs to gh-pages branch of github repo (git should exist on PATH)"
16 | @echo "sdist packages source distribution package"
17 | @echo "sdist-test looks for errors on the source distribution package"
18 | @echo "release packages and uploads a release"
19 |
20 | clean: clean-build clean-pyc clean-tests clean-docs
21 |
22 | clean-build:
23 | rm -rf build/
24 | rm -rf dist/
25 | rm -rf pokepy.egg-info/
26 |
27 | clean-pyc:
28 | find . -name '*.pyc' -exec rm -f {} +
29 | find . -name '*.pyo' -exec rm -f {} +
30 | find . -name '*~' -exec rm -f {} +
31 |
32 | clean-tests:
33 | rm -rf .tox/
34 | rm -rf html_coverage/
35 |
36 | clean-docs:
37 | rm -rf site/
38 |
39 | lint:
40 | python -m pylint --ignore=pokepy/fcache pokepy tests setup.py
41 |
42 | test:
43 | python -m unittest tests.test_pokepy
44 |
45 | test-all:
46 | tox
47 |
48 | coverage:
49 | coverage run --source pokepy --omit="pokepy/fcache/*" -m unittest tests.test_pokepy
50 | coverage report -m
51 | coverage html -d html_coverage
52 | open htmlcov/index.html
53 |
54 | docs-build:
55 | mkdocs build
56 | open site/index.html
57 |
58 | docs-test:
59 | mkdocs serve
60 |
61 | docs-release:
62 | mkdocs gh-deploy --verbose
63 |
64 | sdist: clean-build clean-pyc
65 | python setup.py sdist bdist_wheel
66 |
67 | sdist-test:
68 | twine check dist/*
69 | twine upload --repository-url https://test.pypi.org/legacy/ dist/*
70 |
71 | release: sdist
72 | twine upload dist/*
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pokepy
2 |
3 | [](https://pypi.org/project/pokepy)
4 | [](https://pypi.org/project/pokepy)
5 | [](https://pypi.org/project/pokepy/)
6 | [](https://circleci.com/gh/PokeAPI/pokepy)
7 | [](https://codecov.io/gh/PokeAPI/pokepy)
8 | [](https://snyk.io/test/github/PokeAPI/pokepy?targetFile=requirements.txt)
9 | [](https://github.com/PokeAPI/pokepy/blob/master/LICENSE)
10 |
11 | A python wrapper for [PokéAPI](https://pokeapi.co). (former [pykemon](https://github.com/PokeAPI/pokepy/tree/bb72105f4c5402aaa5d4fd2b9c142bf9b678b254))
12 |
13 | Maintainer: [Kronopt](https://github.com/Kronopt)
14 |
15 | ## Installation
16 |
17 | Nice and simple:
18 |
19 | ```sh
20 | $ pip install pokepy
21 | ```
22 |
23 | ## Usage
24 |
25 | Even simpler:
26 |
27 | ```python
28 | >>> import pokepy
29 | >>> client = pokepy.V2Client()
30 | >>> client.get_pokemon(14)
31 |
32 | ```
33 |
34 | ## Documentation
35 |
36 | For more information, check the documentation at https://pokeapi.github.io/pokepy
37 |
38 | ## Features
39 |
40 | * Generate Python objects from PokéAPI resources
41 | * Cache
42 | * Human-friendly API
43 |
--------------------------------------------------------------------------------
/docs/authors.md:
--------------------------------------------------------------------------------
1 | ### Original Project Lead (Pykemon)
2 | * [Paul Hallett](https://github.com/phalt)
3 |
4 | ### Maintainer
5 | * [Kronopt](https://github.com/Kronopt)
6 |
7 | ### Contributors
8 | * [Owen Hallett](https://github.com/Videocard)
9 | * [Kronopt](https://github.com/Kronopt)
10 | * [Naramsim](https://github.com/Naramsim)
11 |
12 | Made a commit? Add your name to the list!
13 |
--------------------------------------------------------------------------------
/docs/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 | Contributions are welcome, and they are greatly appreciated! Every
3 | little bit helps, and credit will always be given.
4 |
5 | You can contribute in many ways:
6 |
7 | ### Reporting Bugs
8 | Report bugs in the [issues section](https://github.com/PokeAPI/pokepy/issues).
9 |
10 | When reporting a bug, please include:
11 |
12 | * Your operating system name and version.
13 | * Any details about your local setup that might be helpful in troubleshooting.
14 | * Detailed steps to reproduce the bug.
15 |
16 | ### Fixing Bugs
17 | Look through the [issues section](https://github.com/PokeAPI/pokepy/issues) for bugs. Anything tagged with `bug`
18 | is open to whoever wants to implement it.
19 |
20 | ### Implementing Features
21 | Look through the [issues section](https://github.com/PokeAPI/pokepy/issues) for features. Anything tagged with `feature`
22 | is open to whoever wants to implement it.
23 |
24 | When proposing a feature:
25 |
26 | * Explain in detail how it would work.
27 | * Keep the scope as narrow as possible, to make it easier to implement.
28 |
29 | ### Writing Documentation
30 | Pokepy could always use more documentation, whether as part of the
31 | official Pokepy docs, in docstrings, or even on the web in blog posts,
32 | articles, and such.
33 |
34 | ### Submiting Feedback
35 | The best way to send feedback is to file an issue in the [issues section](https://github.com/PokeAPI/pokepy/issues).
36 |
37 | Remember that this is a volunteer-driven project, and that contributions
38 | are welcome :)
39 |
40 | ### Get Started!
41 | Ready to contribute? Here's how to set up `pokepy` for local development.
42 |
43 | **1 .** Fork the `pokepy` repo on GitHub.
44 |
45 | **2 .** Clone your fork locally. You can use a tool like [Github Desktop](https://desktop.github.com/)
46 | or through the command line with `git`:
47 |
48 | ```
49 | $ git clone git@github.com:your_name_here/pokepy.git
50 | ```
51 |
52 | (you can also simply download the project from github as a .zip file)
53 |
54 | **3 .** Install your local copy into a virtual environment.
55 | If you use an IDE, it should have an option to create a new virtual environment.
56 | Otherwise, and assuming you have `virtualenv` installed, this is how you set up your fork for local development:
57 |
58 | ```
59 | $ mkdir venv
60 | $ virtualenv venv/pokepy
61 | $ cd venv/pokepy/bin
62 | $ source activate
63 | $ pip install -r requirements.txt -r requirements-dev.txt
64 | ```
65 |
66 | **4 .** Create a branch for local development (`git`):
67 |
68 | ```
69 | $ git checkout -b name-of-your-bugfix-or-feature
70 | ```
71 |
72 | Now you can make your changes locally.
73 |
74 | **5 .** When you're done making changes, check that your changes pass `pylint` and the `tests`,
75 | including testing other Python versions with `tox`:
76 |
77 | ```
78 | $ python -m pylint pokepy tests setup.py
79 | $ tox
80 | ```
81 |
82 | `pylint` and `tox` should already be installed in your virtualenv if you followed step 3 correctly.
83 |
84 | **6 .** Commit your changes and push your branch to GitHub (`git`):
85 |
86 | ```
87 | $ git add .
88 | $ git commit -m "Your detailed description of your changes"
89 | $ git push origin name-of-your-bugfix-or-feature
90 | ```
91 |
92 | **7 .** Submit a pull request through the GitHub website.
93 |
94 | ### Pull Request Guidelines
95 | Before submiting a pull request, check that it meets these guidelines:
96 |
97 | **1 .** The pull request includes tests (if relevant).
98 |
99 | **2 .** If the pull request adds functionality, the docs should be updated.
100 | Put your new functionality into a function with a docstring, and add the
101 | feature to the list in [README](https://github.com/PokeAPI/pokepy/blob/master/README.md).
102 |
103 | **3 .** The pull request should work for Python 2.7, 3.4, 3.5, 3.6, 3.7 and 3.8.
104 |
105 | ### Tips
106 | To run a subset of tests:
107 |
108 | ```
109 | $ python -m unittest tests.test_pokepy
110 | ```
111 |
--------------------------------------------------------------------------------
/docs/history.md:
--------------------------------------------------------------------------------
1 | # History
2 | ### 0.6.2 (2021-05-16)
3 | * Add `version` subproperty to `FlavorTextSubResource`
4 |
5 | ### 0.6.1 (2020-05-31)
6 | * Fixed disk-based cache not handling different filesystems on Windows
7 |
8 | ### 0.6.0 (2019-05-3)
9 | * V2Client get methods now return element instead of single element list
10 | * set urllib3 version to >=1.24.3, <1.25 (CVE-2019-11236)
11 | * Support for Python 3.4 and 3.5
12 |
13 | ### 0.5.2 (2019-03-01)
14 | * Fixed bug that caused pokemon_encounters subresource to not be detected in LocationAreaResource
15 | (thanks to [jachymb](https://github.com/jachymb))
16 |
17 | ### 0.5.1 (2019-02-16)
18 | * New V2Client cache-related methods:
19 | * cache_info
20 | * cache_clear
21 | * cache_location
22 |
23 | ### 0.5.0 (2019-01-19)
24 | * Pykemon is now Pokepy!
25 | * Cache (disk- and memory-based)
26 |
27 | ### 0.4.0 (2018-10-11)
28 | * Removed code from pre-beckett versions
29 | * Removed V1 API support, as it is now deprecated
30 | * Added some tweaks to the beckett package
31 |
32 | ### 0.3.0 (2017-10-19)
33 | * V2 support added
34 | * Added some missing V1 resources
35 | * Removed files related to API 0.1
36 |
37 | ### 0.2.0 (2016-06-11)
38 | * Beckett API Client framework added
39 |
40 | ### 0.1.2 (2014-1-3)
41 | * Sprite attribute added to Pokemon class
42 |
43 | ### 0.1.1 (2013-12-24)
44 | * Description attribute added to Pokemon class
45 |
46 | ### 0.1.0 (2013-12-23)
47 | * First release on PyPI
48 | * All PokéAPI resources fully supported and represented in an object-oriented style
49 | * Easy-to-use API: just one method!
50 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Pokepy
2 |
3 | [](https://pypi.org/project/pokepy)
4 | [](https://pypi.org/project/pokepy)
5 | [](https://pypi.org/project/pokepy/)
6 | [](https://circleci.com/gh/PokeAPI/pokepy)
7 | [](https://codecov.io/gh/PokeAPI/pokepy)
8 | [](https://snyk.io/test/github/PokeAPI/pokepy?targetFile=requirements.txt)
9 | [](https://github.com/PokeAPI/pokepy/blob/master/LICENSE)
10 |
11 | A python wrapper for [PokéAPI](https://pokeapi.co). (former [pykemon](https://github.com/PokeAPI/pokepy/tree/bb72105f4c5402aaa5d4fd2b9c142bf9b678b254))
12 |
--------------------------------------------------------------------------------
/docs/installation.md:
--------------------------------------------------------------------------------
1 | # Installation
2 | At the command line:
3 | ```bash
4 | $ pip install pokepy
5 | ```
6 |
--------------------------------------------------------------------------------
/docs/stylesheets/extra.css:
--------------------------------------------------------------------------------
1 | .md-header {
2 | background: #ef5350;
3 | }
4 |
--------------------------------------------------------------------------------
/docs/usage.md:
--------------------------------------------------------------------------------
1 | # Usage
2 |
3 | To use Pokepy in a project:
4 |
5 | ```python
6 | >>> import pokepy
7 | ```
8 |
9 | ### API
10 |
11 | Pokepy is composed of a single class, `V2Client`, which implements the whole
12 | [v2 PokéAPI](https://pokeapi.co/docs/v2).
13 | This class is usually instantiated without parameters:
14 |
15 | ```python
16 | >>> client = pokepy.V2Client()
17 | ```
18 |
19 | Unless you want to use the caching feature, which is discussed [further below](#cache).
20 |
21 | Each endpoint of PokéAPI is represented in `V2Client` by a `get_` method,
22 | all taking a single parameter (`uid`), which can be either an `integer` (for most endpoints) or a `string`.
23 |
24 | The following is an exhaustive list of all the endpoints with links to their respective PokéAPI documentation:
25 |
26 | - [get_berry](https://pokeapi.co/docs/v2#berries)
27 | - [get_berry_firmness](https://pokeapi.co/docs/v2#berry-firmnesses)
28 | - [get_berry_flavor](https://pokeapi.co/docs/v2#berry-flavors)
29 | - [get_contest_type](https://pokeapi.co/docs/v2#contest-types)
30 | - [get_contest_effect](https://pokeapi.co/docs/v2#contest-effects)
31 | - [get_super_contest_effect](https://pokeapi.co/docs/v2#super-contest-effects)
32 | - [get_encounter_method](https://pokeapi.co/docs/v2#encounter-methods)
33 | - [get_encounter_condition](https://pokeapi.co/docs/v2#encounter-conditions)
34 | - [get_encounter_condition_value](https://pokeapi.co/docs/v2#encounter-condition-values)
35 | - [get_evolution_chain](https://pokeapi.co/docs/v2#evolution-chains)
36 | - [get_evolution_trigger](https://pokeapi.co/docs/v2#evolution-triggers)
37 | - [get_generation](https://pokeapi.co/docs/v2#generations)
38 | - [get_pokedex](https://pokeapi.co/docs/v2#pokedexes)
39 | - [get_version](https://pokeapi.co/docs/v2#version)
40 | - [get_version_group](https://pokeapi.co/docs/v2#version-groups)
41 | - [get_item](https://pokeapi.co/docs/v2#item)
42 | - [get_item_attribute](https://pokeapi.co/docs/v2#item-attributes)
43 | - [get_item_category](https://pokeapi.co/docs/v2#item-categories)
44 | - [get_item_fling_effect](https://pokeapi.co/docs/v2#item-fling-effects)
45 | - [get_item_pocket](https://pokeapi.co/docs/v2#item-pockets)
46 | - [get_location](https://pokeapi.co/docs/v2#locations)
47 | - [get_location_area](https://pokeapi.co/docs/v2#location-areas)
48 | - [get_pal_park_area](https://pokeapi.co/docs/v2#pal-park-areas)
49 | - [get_region](https://pokeapi.co/docs/v2#regions)
50 | - [get_machine](https://pokeapi.co/docs/v2#machines)
51 | - [get_move](https://pokeapi.co/docs/v2#moves)
52 | - [get_move_ailment](https://pokeapi.co/docs/v2#move-ailments)
53 | - [get_move_battle_style](https://pokeapi.co/docs/v2#move-battle-styles)
54 | - [get_move_category](https://pokeapi.co/docs/v2#move-categories)
55 | - [get_move_damage_class](https://pokeapi.co/docs/v2#move-damage-classes)
56 | - [get_move_learn_method](https://pokeapi.co/docs/v2#move-learn-methods)
57 | - [get_move_target](https://pokeapi.co/docs/v2#move-targets)
58 | - [get_ability](https://pokeapi.co/docs/v2#abilities)
59 | - [get_characteristic](https://pokeapi.co/docs/v2#characteristics)
60 | - [get_egg_group](https://pokeapi.co/docs/v2#egg-groups)
61 | - [get_gender](https://pokeapi.co/docs/v2#genders)
62 | - [get_growth_rate](https://pokeapi.co/docs/v2#growth-rates)
63 | - [get_nature](https://pokeapi.co/docs/v2#natures)
64 | - [get_pokeathlon_stat](https://pokeapi.co/docs/v2#pokeathlon-stats)
65 | - [get_pokemon](https://pokeapi.co/docs/v2#pokemon)
66 | - [get_pokemon_color](https://pokeapi.co/docs/v2#pok%C3%A9mon-colors)
67 | - [get_pokemon_form](https://pokeapi.co/docs/v2#pok%C3%A9mon-forms)
68 | - [get_pokemon_habitat](https://pokeapi.co/docs/v2#pok%C3%A9mon-habitats)
69 | - [get_pokemon_shape](https://pokeapi.co/docs/v2#pok%C3%A9mon-shapes)
70 | - [get_pokemon_species](https://pokeapi.co/docs/v2#pok%C3%A9mon-species)
71 | - [get_stat](https://pokeapi.co/docs/v2#stats)
72 | - [get_type](https://pokeapi.co/docs/v2#types)
73 | - [get_language](https://pokeapi.co/docs/v2#languages)
74 |
75 | Each method returns an object containing as many python attributes as there are named attributes.
76 | Please refer to the [PokéAPI documentation](https://pokeapi.co/docs/v2)
77 | for more information on what each of these methods returns, its description and type.
78 |
79 | Then you can start grabbing stuff from the API:
80 |
81 | ```python
82 | >>> mew = pokepy.V2Client().get_pokemon('mew')
83 | >>> mew
84 |
85 | >>> mew.name
86 | mew
87 | ```
88 |
89 | ```python
90 | >>> kakuna = pokepy.V2Client().get_pokemon(14)
91 | >>> kakuna
92 |
93 | >>> kakuna.weigth
94 | 100
95 | ```
96 |
97 | ```python
98 | >>> cut = pokepy.V2Client().get_move(15)
99 | >>> cut
100 |
101 | >>> cut.power
102 | 50
103 | ```
104 |
105 | Some resources have subresources:
106 |
107 | ```python
108 | >>> kakuna = pokepy.V2Client().get_pokemon(14)
109 | >>> kakuna
110 |
111 | >>> kakuna.types
112 | [, ]
113 | >>> kakuna.types[0].type.name
114 | poison
115 | ```
116 |
117 | ```python
118 | >>> insomnia = pokepy.V2Client().get_ability(15)
119 | >>> insomnia
120 |
121 | >>> insomnia.effect_entries[0].short_effect
122 | Prevents sleep.
123 | ```
124 |
125 | ### Parameters
126 |
127 | Most resources can be requested by using either the `name` or `id` of the resource:
128 |
129 | ```python
130 | >>> pokepy.V2Client().get_pokemon('rotom')
131 |
132 | >>> pokepy.V2Client().get_pokemon(479)
133 |
134 | >>> pokepy.V2Client().get_pokemon('479')
135 |
136 | ```
137 |
138 | ### Cache
139 |
140 | If you use the API to get the same resources often,
141 | you can enable cache to avoid making unnecessary requests to the PokéAPI server.
142 | You can either enable `memory-based` or `disk-based` cache.
143 |
144 | #### Memory-based
145 |
146 | Memory-based cache is activated by passing `in_memory` to the `cache` parameter of `V2Client`.
147 | Resources obtained from the PokéAPI are then saved in RAM. Cache is kept per get method:
148 |
149 | ```python
150 | >>> client_mem_cache = pokepy.V2Client(cache='in_memory')
151 | ```
152 |
153 | You can check the state of the cache in two ways: per get method or as a whole.
154 |
155 | To check the state of the cache of a particular method, call the `cache_info()`
156 | of that get method:
157 |
158 | ```python
159 | >>> client_mem_cache.get_pokemon.cache_info()
160 | CacheInfo(hits=0, misses=0, size=0)
161 | ```
162 |
163 | To check the state of the cache as a whole (all get methods combined),
164 | call the `cache_info()` of `V2Client`:
165 |
166 | ```python
167 | >>> client_mem_cache.cache_info()
168 | CacheInfo(hits=0, misses=0, size=0)
169 | ```
170 |
171 | `hits` is the number of previously cached parametes which were returned,
172 | `misses` is the number given parameters not previously cached (which are now cached),
173 | and `size` is the total number of cached parameters.
174 |
175 | When calling a certain endpoint, the `cache_info` reflects that call:
176 |
177 | ```python
178 | >>> kakuna = client_mem_cache.get_pokemon(14)
179 | >>> client_mem_cache.get_pokemon.cache_info()
180 | CacheInfo(hits=0, misses=1, size=1)
181 | ```
182 |
183 | Calling the same resource as before with the same parameters will retrieve
184 | the cached resource instead of getting it from the server:
185 |
186 | ```python
187 | >>> kakuna = client_mem_cache.get_pokemon(14)
188 | >>> client_mem_cache.get_pokemon.cache_info()
189 | CacheInfo(hits=1, misses=1, size=1)
190 | ```
191 |
192 | To clear the cache of a specific get method:
193 |
194 | ```python
195 | >>> client_mem_cache.get_pokemon.cache_clear()
196 | >>> client_mem_cache.get_pokemon.cache_info()
197 | CacheInfo(hits=0, misses=0, size=0)
198 | ```
199 |
200 | To clear all cache:
201 |
202 | ```python
203 | >>> client_mem_cache.cache_clear()
204 | >>> client_mem_cache.cache_info()
205 | CacheInfo(hits=0, misses=0, size=0)
206 | ```
207 |
208 | #### Disk-based
209 |
210 | Disk-based cache is activated by passing `in_disk` to the `cache` parameter of `V2Client`.
211 | Resources obtained from the PokéAPI are then saved to disk. Cache is kept per get method:
212 |
213 | ```python
214 | >>> client_disk_cache = pokepy.V2Client(cache='in_disk', cache_location='/temp')
215 | ```
216 |
217 | In this case it's possible to specify the cache directory with the `cache_location` parameter.
218 | A folder named `pokepy_cache` will be created inside the specified directory, where the
219 | cache of each get method will be located.
220 | If no cache directory is specified a system-appropriate cache directory is automatically determined by
221 | [appdirs](https://pypi.org/project/appdirs/).
222 |
223 | The methods used to check the state and clear the cache are the same as in the memory-based cache,
224 | including the global `V2Client` methods.
225 |
226 | You can also check the cache directory, per get method:
227 |
228 | ```python
229 | >>> client_disk_cache.get_pokemon.cache_location()
230 | /temp/pokepy_cache/39/cache
231 | ```
232 |
233 | Or check the global cache directory:
234 |
235 | ```python
236 | >>> client_disk_cache.cache_location()
237 | /temp/pokepy_cache/
238 | ```
239 |
240 | Disk-based cache is reloaded automatically between runs if the same cache directory is specified.
241 |
--------------------------------------------------------------------------------
/make.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | if "%1" == "" goto help
4 | goto %~1
5 |
6 | :help
7 | echo.
8 | echo clean removes build and python file artifacts
9 | echo clean-build removes build artifacts
10 | echo clean-pyc removes python file artifacts
11 | echo clean-tests removes test and coverage files
12 | echo clean-docs removes built docs files
13 | echo lint checks style with pylint
14 | echo test runs tests quickly with the default python version
15 | echo test-all runs tests on every python version with tox
16 | echo coverage checks code coverage quickly with the default python version
17 | echo docs-build builds MkDocs HTML documentation
18 | echo docs-test live tests the current documentation
19 | echo docs-release pushes built docs to gh-pages branch of github repo (git should exist on PATH)
20 | echo sdist packages source distribution package
21 | echo sdist-test looks for errors on the source distribution package
22 | echo release packages and uploads a release
23 | goto:eof
24 |
25 | :clean
26 | call:clean-build
27 | call:clean-pyc
28 | call:clean-tests
29 | call:clean-docs
30 | goto:eof
31 |
32 | :clean-build
33 | rmdir /s /q build
34 | rmdir /s /q dist
35 | rmdir /s /q pokepy.egg-info
36 | goto:eof
37 |
38 | :clean-pyc
39 | del /s *.pyc *.pyo *~
40 | goto:eof
41 |
42 | :clean-tests
43 | rmdir /s /q .tox
44 | rmdir /s /q html_coverage
45 | goto:eof
46 |
47 | :clean-docs
48 | rmdir /s /q site
49 | goto:eof
50 |
51 | :lint
52 | python -m pylint --ignore=pokepy\fcache pokepy tests setup.py
53 | goto:eof
54 |
55 | :test
56 | python -m unittest tests.test_pokepy
57 | goto:eof
58 |
59 | :test-all
60 | tox
61 | goto:eof
62 |
63 | :coverage
64 | coverage run --source pokepy --omit="pokepy\fcache\*" -m unittest tests.test_pokepy
65 | coverage report -m
66 | coverage html -d html_coverage
67 | start "" html_coverage/index.html
68 | goto:eof
69 |
70 | :docs-build
71 | mkdocs build
72 | start "" site/index.html
73 | goto:eof
74 |
75 | :docs-test
76 | mkdocs serve
77 | goto:eof
78 |
79 | :docs-release
80 | mkdocs gh-deploy --verbose
81 | goto:eof
82 |
83 | :sdist
84 | call:clean-build
85 | call:clean-pyc
86 | python setup.py sdist bdist_wheel
87 | goto:eof
88 |
89 | :sdist-test
90 | twine check dist/*
91 | twine upload --repository-url https://test.pypi.org/legacy/ dist/*
92 | goto:eof
93 |
94 | :release
95 | call:sdist
96 | twine upload dist/*
97 | goto:eof
98 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: Pokepy
2 | theme:
3 | name: 'material'
4 |
5 | nav:
6 | - Home: 'index.md'
7 | - Installation: 'installation.md'
8 | - Usage: 'usage.md'
9 | - Contributing: 'contributing.md'
10 | - Authors: 'authors.md'
11 | - History: 'history.md'
12 |
13 | extra_css:
14 | - 'stylesheets/extra.css'
15 |
--------------------------------------------------------------------------------
/pokepy/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 | """
5 | Pokepy
6 |
7 | A Python wrapper for PokéAPI (https://pokeapi.co)
8 |
9 | Usage:
10 | >>> import pokepy
11 | >>> clientV2 = pokepy.V2Client()
12 | >>> clientV2.get_pokemon('bulbasaur')
13 |
14 | """
15 |
16 | __author__ = 'Paul Hallett'
17 | __email__ = 'hello@phalt.co'
18 | __credits__ = ["Paul Hallett", "Owen Hallett", "Kronopt"]
19 | __version__ = '0.6.2'
20 | __copyright__ = 'Copyright Paul Hallett 2016'
21 | __license__ = 'BSD'
22 |
23 |
24 | from .api import V2Client
25 |
--------------------------------------------------------------------------------
/pokepy/api.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 | """
5 | pokepy.api
6 |
7 | User interaction with this package is done through this file.
8 | """
9 |
10 | import functools
11 | import os
12 | import sys
13 | import types
14 | from collections import namedtuple
15 | import appdirs # dependency of FileCache
16 | from beckett.clients import BaseClient
17 | from beckett.constants import DEFAULT_VALID_STATUS_CODES
18 | from .fcache.cache import FileCache
19 | from . import resources_v2 as rv2
20 | from . import __version__
21 |
22 |
23 | class V2Client(BaseClient):
24 | """Pokéapi client"""
25 |
26 | class Meta(BaseClient.Meta):
27 | name = 'pokepy-v2-client-' + __version__
28 | base_url = 'https://pokeapi.co/api/v2'
29 | resources = (
30 | rv2.BerryResource,
31 | rv2.BerryFirmnessResource,
32 | rv2.BerryFlavorResource,
33 | rv2.ContestTypeResource,
34 | rv2.ContestEffectResource,
35 | rv2.SuperContestEffectResource,
36 | rv2.EncounterMethodResource,
37 | rv2.EncounterConditionResource,
38 | rv2.EncounterConditionValueResource,
39 | rv2.EvolutionChainResource,
40 | rv2.EvolutionTriggerResource,
41 | rv2.GenerationResource,
42 | rv2.PokedexResource,
43 | rv2.VersionResource,
44 | rv2.VersionGroupResource,
45 | rv2.ItemResource,
46 | rv2.ItemAttributeResource,
47 | rv2.ItemCategoryResource,
48 | rv2.ItemFlingEffectResource,
49 | rv2.ItemPocketResource,
50 | rv2.MachineResource,
51 | rv2.MoveResource,
52 | rv2.MoveAilmentResource,
53 | rv2.MoveBattleStyleResource,
54 | rv2.MoveCategoryResource,
55 | rv2.MoveDamageClassResource,
56 | rv2.MoveLearnMethodResource,
57 | rv2.MoveTargetResource,
58 | rv2.LocationResource,
59 | rv2.LocationAreaResource,
60 | rv2.PalParkAreaResource,
61 | rv2.RegionResource,
62 | rv2.AbilityResource,
63 | rv2.CharacteristicResource,
64 | rv2.EggGroupResource,
65 | rv2.GenderResource,
66 | rv2.GrowthRateResource,
67 | rv2.NatureResource,
68 | rv2.PokeathlonStatResource,
69 | rv2.PokemonResource,
70 | rv2.PokemonColorResource,
71 | rv2.PokemonFormResource,
72 | rv2.PokemonHabitatResource,
73 | rv2.PokemonShapeResource,
74 | rv2.PokemonSpeciesResource,
75 | rv2.StatResource,
76 | rv2.TypeResource,
77 | rv2.LanguageResource
78 | )
79 |
80 | def __init__(self, cache=None, cache_location=None, *args, **kwargs):
81 | """
82 | Parameters
83 | ----------
84 | cache: str
85 | cache can be 'in_memory' or 'in_disk',
86 | for memory-based or disk-based cache, respectively.
87 | Optional.
88 | cache_location: str
89 | cache directory, for disk-based cache.
90 | Optional.
91 | """
92 | if cache is None: # empty wrapping function
93 | def no_cache(func):
94 | @functools.wraps(func)
95 | def inner(*args, **kwargs):
96 | return func(*args, **kwargs)
97 | return inner
98 | cache_function = no_cache
99 | else:
100 | if cache in ['in_memory', 'in_disk']:
101 | cache_function = self._caching(cache.split('in_')[1], cache_location)
102 | self.cache_type = cache
103 |
104 | def cache_info_total(self):
105 | return self._cache_info_(self._cache_hits_global,
106 | self._cache_misses_global,
107 | self._cache_len_global)
108 |
109 | def cache_clear_total(self):
110 | for get_method_name in self._all_get_methods_names:
111 | getattr(self, get_method_name).cache_clear()
112 |
113 | def cache_location_absolute(self):
114 | return self._cache_location_global
115 |
116 | # global cache related methods
117 | self.cache_info = types.MethodType(cache_info_total, self)
118 | self.cache_clear = types.MethodType(cache_clear_total, self)
119 | self.cache_location = types.MethodType(cache_location_absolute, self)
120 |
121 | self._cache_hits_global = 0
122 | self._cache_misses_global = 0
123 | self._cache_len_global = 0
124 | self._cache_location_global = ''
125 | self._cache_info_ = namedtuple('CacheInfo', ['hits', 'misses', 'size'])
126 | else: # wrong cache parameter
127 | raise ValueError('Accepted values for cache are "in_memory" or "in_disk"')
128 |
129 | self._cache = cache_function
130 | self._all_get_methods_names = []
131 | super(V2Client, self).__init__(*args, **kwargs)
132 |
133 | def _assign_method(self, resource_class, method_type):
134 | """
135 | Exactly the same code as the original except:
136 | - uid is now first parameter (after self). Therefore, no need to explicitly call 'uid='
137 | - Ignored the other http methods besides GET (as they are not needed for the pokeapi.co API)
138 | - Added cache wrapping function
139 | - Added a way to list all get methods
140 | - Added a filter for single element lists (extract element into a standalone object)
141 | """
142 | method_name = resource_class.get_method_name(
143 | resource_class, method_type)
144 | valid_status_codes = getattr(
145 | resource_class.Meta,
146 | 'valid_status_codes',
147 | DEFAULT_VALID_STATUS_CODES
148 | )
149 |
150 | def extract_single_element_list(func):
151 | @functools.wraps(func)
152 | def inner(*args, **kwargs):
153 | final = func(*args, **kwargs)
154 | if len(final) == 1:
155 | final = final[0]
156 | return final
157 | return inner
158 |
159 | # uid is now the first argument (after self)
160 | @self._cache
161 | @extract_single_element_list
162 | def get(self, uid=None, method_type=method_type,
163 | method_name=method_name,
164 | valid_status_codes=valid_status_codes,
165 | resource=resource_class, data=None, **kwargs):
166 | uid = uid.lower() if isinstance(uid, str) else uid
167 | return self.call_api(
168 | method_type, method_name,
169 | valid_status_codes, resource,
170 | data, uid=uid, **kwargs)
171 |
172 | # only GET method is used
173 | setattr(
174 | self, method_name,
175 | types.MethodType(get, self)
176 | )
177 |
178 | # for easier listing of get methods
179 | self._all_get_methods_names.append(method_name)
180 |
181 | def _caching(self, disk_or_memory, cache_directory=None):
182 | """
183 | Decorator that allows caching the outputs of the BaseClient get methods.
184 | Cache can be either disk- or memory-based.
185 | Disk-based cache is reloaded automatically between runs if the same
186 | cache directory is specified.
187 | Cache is kept per each unique uid.
188 |
189 | ex:
190 | >> client.get_pokemon(1) -> output gets cached
191 | >> client.get_pokemon(uid=1) -> output already cached
192 | >> client.get_pokemon(2) -> output gets cached
193 |
194 | Parameters
195 | ----------
196 | disk_or_memory: str
197 | Specify if the cache is disk- or memory-based. Accepts 'disk' or 'memory'.
198 | cache_directory: str
199 | Specify the directory for the disk-based cache.
200 | Optional, will chose an appropriate and platform-specific directory if not specified.
201 | Ignored if memory-based cache is selected.
202 | """
203 | if disk_or_memory not in ('disk', 'memory'):
204 | raise ValueError('Accepted values are "disk" or "memory"')
205 |
206 | # Because of how BaseClient get methods are generated, they don't get a proper __name__.
207 | # As such, it is hard to generate a specific cache directory name for each get method.
208 | # Therefore, I decided to just generate a number for each folder, starting at zero.
209 | # The same get methods get the same number every time because their order doesn't change.
210 | # Also, variable is incremented inside a list because nonlocals are only python 3.0 and up.
211 | get_methods_id = [0]
212 |
213 | def memoize(func):
214 | _global_cache_dir = ''
215 |
216 | if disk_or_memory == 'disk':
217 | if cache_directory:
218 | # Python 2 and 3.4 workaround
219 | if (sys.version_info[0] == 2 and not
220 | isinstance(cache_directory, (str, unicode))) or (
221 | sys.version_info[0:2] == (3, 4) and not
222 | isinstance(cache_directory, str)):
223 | raise TypeError('expected str, not %s' % cache_directory.__class__.__name__)
224 |
225 | _global_cache_dir = os.path.join(cache_directory, 'pokepy_cache')
226 | cache_dir = os.path.join(_global_cache_dir, str(get_methods_id[0]))
227 | else:
228 | _global_cache_dir = appdirs.user_cache_dir('pokepy_cache', False,
229 | opinion=False)
230 | cache_dir = os.path.join(_global_cache_dir, str(get_methods_id[0]))
231 |
232 | cache = FileCache('pokepy', flag='cs', app_cache_dir=cache_dir)
233 | get_methods_id[0] += 1
234 | else: # 'memory'
235 | cache = {}
236 | _global_cache_dir = 'ram'
237 |
238 | # global cache directory
239 | # should only be set when setting the first get method
240 | if not self._cache_location_global:
241 | self._cache_location_global = _global_cache_dir
242 |
243 | hits = [0]
244 | misses = [0]
245 |
246 | def cache_info():
247 | return self._cache_info_(hits[0], misses[0], len(cache))
248 |
249 | def cache_clear():
250 | # global cache info
251 | self._cache_hits_global -= hits[0]
252 | self._cache_misses_global -= misses[0]
253 | self._cache_len_global -= len(cache)
254 | # local cache info
255 | hits[0] = 0
256 | misses[0] = 0
257 |
258 | cache.clear() # for disk-based cache, files are deleted but not the directories
259 | if disk_or_memory == 'disk':
260 | cache.create() # recreate cache file handles
261 |
262 | def cache_location():
263 | return 'ram' if disk_or_memory == 'memory' else cache.cache_dir
264 |
265 | @functools.wraps(func)
266 | def memoizer(*args, **kwargs):
267 | # arguments to the get methods can be a value or uid=value
268 | key = str(args[1]) if len(args) > 1 else str(kwargs.get("uid"))
269 |
270 | if key not in cache:
271 | # local and global cache info
272 | misses[0] += 1
273 | self._cache_misses_global += 1
274 | cache[key] = func(*args, **kwargs)
275 | self._cache_len_global += 1
276 | else:
277 | self._cache_hits_global += 1 # global cache info
278 | hits[0] += 1 # local cache info
279 | return cache[key]
280 |
281 | memoizer.cache_info = cache_info
282 | memoizer.cache_clear = cache_clear
283 | memoizer.cache_location = cache_location
284 | return memoizer
285 |
286 | return memoize
287 |
--------------------------------------------------------------------------------
/pokepy/fcache/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 | """
5 | fcache
6 |
7 | Same codebase as fcache 0.4.7 (https://pypi.org/project/fcache/)
8 | except for a single fix (https://github.com/tsroten/fcache/pull/29)
9 | """
10 |
--------------------------------------------------------------------------------
/pokepy/fcache/cache.py:
--------------------------------------------------------------------------------
1 | import codecs
2 | import logging
3 | import os
4 | import pickle
5 | import shutil
6 | import tempfile
7 |
8 | import appdirs
9 |
10 | try:
11 | from collections.abc import MutableMapping
12 | unicode = str
13 | except ImportError:
14 | # Python 2 imports
15 | from collections import MutableMapping
16 | FileNotFoundError = IOError
17 |
18 | from .posixemulation import rename
19 |
20 | logger = logging.getLogger(__name__)
21 |
22 |
23 | class FileCache(MutableMapping):
24 | """A persistent file cache that is dictionary-like and has a write buffer.
25 |
26 | *appname* is passed to `appdirs `_
27 | to determine a system-appropriate location for the cache files. The cache
28 | directory used is available via :data:`cache_dir`.
29 |
30 | By default, a write buffer is used, so writing to cache files is not done
31 | until :meth:`sync` is explicitly called. This behavior can be changed using
32 | the optional *flag* argument.
33 |
34 | .. NOTE::
35 | Keys and values are always stored as :class:`bytes` objects. If data
36 | serialization is enabled, keys are returned as :class:`str` or
37 | :class:`unicode` objects.
38 | If data serialization is disabled, keys are returned as a
39 | :class:`bytes` object.
40 |
41 | :param str appname: The app/script the cache should be associated with.
42 | :param str flag: How the cache should be opened. See below for details.
43 | :param mode: The Unix mode for the cache files.
44 | :param str keyencoding: The encoding the keys use, defaults to 'utf-8'.
45 | This is used if *serialize* is ``False``; the keys are treated as
46 | :class:`bytes` objects.
47 | :param bool serialize: Whether or not to (de)serialize the values. If a
48 | cache is used with a :class:`~shelve.Shelf`, set this to ``False``.
49 | :param str app_cache_dir: absolute path to root cache directory to be
50 | used in place of system-appropriate location determined by appdirs
51 |
52 | The optional *flag* argument can be:
53 |
54 | +---------+-------------------------------------------+
55 | | Value | Meaning |
56 | +=========+===========================================+
57 | | ``'r'`` | Open existing cache for reading only |
58 | +---------+-------------------------------------------+
59 | | ``'w'`` | Open existing cache for reading and |
60 | | | writing |
61 | +---------+-------------------------------------------+
62 | | ``'c'`` | Open cache for reading and writing, |
63 | | | creating it if it doesn't exist (default) |
64 | +---------+-------------------------------------------+
65 | | ``'n'`` | Always create a new, empty cache, open |
66 | | | for reading and writing |
67 | +---------+-------------------------------------------+
68 |
69 | If a ``'s'`` is appended to the *flag* argument, the cache will be opened
70 | in sync mode. Writing to the cache will happen immediately and will not be
71 | buffered.
72 |
73 | If an application needs to use more than one cache, then it should use
74 | subcaches. To create a subcache, append a series of one or more names
75 | separated by periods to the application name when creating a
76 | :class:`FileCache` object (e.g. ``'appname.subcache'`` or
77 | ``'appname.subcache.subcache'``).
78 | Subcaches are a way for an application to use more than one cache without
79 | polluting a user's cache directory. All caches -- main caches or subcaches
80 | -- are totally independent. The only aspect in which they are linked is
81 | that all of an application's caches exist in the same system directory.
82 | Because each cache is independent of every other cache, calling
83 | :meth:`delete` on an application's main cache will not delete data in
84 | its subcaches.
85 |
86 | """
87 |
88 | def __init__(self, appname, flag='c', mode=0o666, keyencoding='utf-8',
89 | serialize=True, app_cache_dir=None):
90 | """Initialize a :class:`FileCache` object."""
91 | if not isinstance(flag, str):
92 | raise TypeError("flag must be str not '{}'".format(type(flag)))
93 | elif flag[0] not in 'rwcn':
94 | raise ValueError("invalid flag: '{}', first flag must be one of "
95 | "'r', 'w', 'c' or 'n'".format(flag))
96 | elif len(flag) > 1 and flag[1] != 's':
97 | raise ValueError("invalid flag: '{}', second flag must be "
98 | "'s'".format(flag))
99 |
100 | appname, subcache = self._parse_appname(appname)
101 | if 'cache' in subcache:
102 | raise ValueError("invalid subcache name: 'cache'.")
103 | self._is_subcache = bool(subcache)
104 |
105 | if not app_cache_dir:
106 | app_cache_dir = appdirs.user_cache_dir(appname, appname)
107 | subcache_dir = os.path.join(app_cache_dir, *subcache)
108 | self.cache_dir = os.path.join(subcache_dir, 'cache')
109 | exists = os.path.exists(self.cache_dir)
110 |
111 | if len(flag) > 1 and flag[1] == 's':
112 | self._sync = True
113 | else:
114 | self._sync = False
115 | self._buffer = {}
116 |
117 | if exists and 'n' in flag:
118 | self.clear()
119 | self.create()
120 | elif not exists and ('c' in flag or 'n' in flag):
121 | self.create()
122 | elif not exists:
123 | raise FileNotFoundError("no such directory: '{}'".format(
124 | self.cache_dir))
125 |
126 | self._flag = 'rb' if 'r' in flag else 'wb'
127 | self._mode = mode
128 | self._keyencoding = keyencoding
129 | self._serialize = serialize
130 |
131 | def _parse_appname(self, appname):
132 | """Splits an appname into the appname and subcache components."""
133 | components = appname.split('.')
134 | return components[0], components[1:]
135 |
136 | def create(self):
137 | """Create the write buffer and cache directory."""
138 | if not self._sync and not hasattr(self, '_buffer'):
139 | self._buffer = {}
140 | if not os.path.exists(self.cache_dir):
141 | os.makedirs(self.cache_dir)
142 |
143 | def clear(self):
144 | """Remove all items from the write buffer and cache.
145 |
146 | The write buffer object and cache directory are not deleted.
147 |
148 | """
149 | self.delete()
150 | self.create()
151 |
152 | def delete(self):
153 | """Delete the write buffer and cache directory."""
154 | if not self._sync:
155 | del self._buffer
156 | shutil.rmtree(self.cache_dir)
157 |
158 | def close(self):
159 | """Sync the write buffer, then close the cache.
160 |
161 | If a closed :class:`FileCache` object's methods are called, a
162 | :exc:`ValueError` will be raised.
163 |
164 | """
165 | self.sync()
166 | self.sync = self.create = self.delete = self._closed
167 | self._write_to_file = self._read_to_file = self._closed
168 | self._key_to_filename = self._filename_to_key = self._closed
169 | self.__getitem__ = self.__setitem__ = self.__delitem__ = self._closed
170 | self.__iter__ = self.__len__ = self.__contains__ = self._closed
171 |
172 | def sync(self):
173 | """Sync the write buffer with the cache files and clear the buffer.
174 |
175 | If the :class:`FileCache` object was opened with the optional ``'s'``
176 | *flag* argument, then calling :meth:`sync` will do nothing.
177 | """
178 | if self._sync:
179 | return # opened in sync mode, so skip the manual sync
180 | self._sync = True
181 | for ekey in self._buffer:
182 | filename = self._key_to_filename(ekey)
183 | self._write_to_file(filename, self._buffer[ekey])
184 | self._buffer.clear()
185 | self._sync = False
186 |
187 | def _closed(self, *args, **kwargs):
188 | """Filler method for closed cache methods."""
189 | raise ValueError("invalid operation on closed cache")
190 |
191 | def _encode_key(self, key):
192 | """Encode key using *hex_codec* for constructing a cache filename.
193 |
194 | Keys are implicitly converted to :class:`bytes` if passed as
195 | :class:`str`.
196 |
197 | """
198 | if isinstance(key, str) or isinstance(key, unicode):
199 | key = key.encode(self._keyencoding)
200 | elif not isinstance(key, bytes):
201 | raise TypeError("key must be bytes or str")
202 | return codecs.encode(key, 'hex_codec').decode(self._keyencoding)
203 |
204 | def _decode_key(self, key):
205 | """Decode key using hex_codec to retrieve the original key.
206 |
207 | Keys are returned as :class:`str` if serialization is enabled.
208 | Keys are returned as :class:`bytes` if serialization is disabled.
209 |
210 | """
211 | bkey = codecs.decode(key.encode(self._keyencoding), 'hex_codec')
212 | return bkey.decode(self._keyencoding) if self._serialize else bkey
213 |
214 | def _dumps(self, value):
215 | return value if not self._serialize else pickle.dumps(value)
216 |
217 | def _loads(self, value):
218 | return value if not self._serialize else pickle.loads(value)
219 |
220 | def _key_to_filename(self, key):
221 | """Convert an encoded key to an absolute cache filename."""
222 | return os.path.join(self.cache_dir, key)
223 |
224 | def _filename_to_key(self, absfilename):
225 | """Convert an absolute cache filename to a key name."""
226 | return os.path.split(absfilename)[1]
227 |
228 | def _all_filenames(self):
229 | """Return a list of absolute cache filenames"""
230 | try:
231 | return [os.path.join(self.cache_dir, filename) for filename in
232 | os.listdir(self.cache_dir)]
233 | except (FileNotFoundError, OSError):
234 | return []
235 |
236 | def _all_keys(self):
237 | """Return a list of all encoded key names."""
238 | file_keys = [self._filename_to_key(fn) for fn in self._all_filenames()]
239 | if self._sync:
240 | return set(file_keys)
241 | else:
242 | return set(file_keys + list(self._buffer))
243 |
244 | def _write_to_file(self, filename, bytesvalue):
245 | """Write bytesvalue to filename."""
246 | fh, tmp = tempfile.mkstemp()
247 | with os.fdopen(fh, self._flag) as f:
248 | f.write(self._dumps(bytesvalue))
249 | rename(tmp, filename)
250 | os.chmod(filename, self._mode)
251 |
252 | def _read_from_file(self, filename):
253 | """Read data from filename."""
254 | try:
255 | with open(filename, 'rb') as f:
256 | return self._loads(f.read())
257 | except (IOError, OSError):
258 | logger.warning('Error opening file: {}'.format(filename))
259 | return None
260 |
261 | def __setitem__(self, key, value):
262 | ekey = self._encode_key(key)
263 | if not self._sync:
264 | self._buffer[ekey] = value
265 | else:
266 | filename = self._key_to_filename(ekey)
267 | self._write_to_file(filename, value)
268 |
269 | def __getitem__(self, key):
270 | ekey = self._encode_key(key)
271 | if not self._sync:
272 | try:
273 | return self._buffer[ekey]
274 | except KeyError:
275 | pass
276 | filename = self._key_to_filename(ekey)
277 | if filename not in self._all_filenames():
278 | raise KeyError(key)
279 | return self._read_from_file(filename)
280 |
281 | def __delitem__(self, key):
282 | ekey = self._encode_key(key)
283 | filename = self._key_to_filename(ekey)
284 | if not self._sync:
285 | try:
286 | del self._buffer[ekey]
287 | except KeyError:
288 | if filename not in self._all_filenames():
289 | raise KeyError(key)
290 | try:
291 | os.remove(filename)
292 | except (IOError, OSError):
293 | pass
294 |
295 | def __iter__(self):
296 | for key in self._all_keys():
297 | yield self._decode_key(key)
298 |
299 | def __len__(self):
300 | return len(self._all_keys())
301 |
302 | def __contains__(self, key):
303 | ekey = self._encode_key(key)
304 | return ekey in self._all_keys()
305 |
--------------------------------------------------------------------------------
/pokepy/fcache/posixemulation.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | r"""
3 | werkzeug.posixemulation
4 | ~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | Provides a POSIX emulation for some features that are relevant to
7 | web applications. The main purpose is to simplify support for
8 | systems such as Windows NT that are not 100% POSIX compatible.
9 |
10 | Currently this only implements a :func:`rename` function that
11 | follows POSIX semantics. Eg: if the target file already exists it
12 | will be replaced without asking.
13 |
14 | This module was introduced in 0.6.1 and is not a public interface.
15 | It might become one in later versions of Werkzeug.
16 |
17 | :copyright: (c) 2013 by the Werkzeug Team, see AUTHORS for more details.
18 | :license: BSD, see LICENSE for more details.
19 | """
20 | import sys
21 | import os
22 | import errno
23 | import time
24 | import random
25 | import shutil
26 |
27 |
28 | can_rename_open_file = False
29 | if os.name == 'nt': # pragma: no cover
30 | _rename = lambda src, dst: False
31 | _rename_atomic = lambda src, dst: False
32 | if sys.version_info >= (3, 0):
33 | unicode = str
34 |
35 | try:
36 | import ctypes
37 |
38 | _MOVEFILE_REPLACE_EXISTING = 0x1
39 | _MOVEFILE_WRITE_THROUGH = 0x8
40 | _MoveFileEx = ctypes.windll.kernel32.MoveFileExW
41 |
42 | def _rename(src, dst):
43 | if not isinstance(src, unicode):
44 | src = unicode(src, sys.getfilesystemencoding())
45 | if not isinstance(dst, unicode):
46 | dst = unicode(dst, sys.getfilesystemencoding())
47 | if _rename_atomic(src, dst):
48 | return True
49 | retry = 0
50 | rv = False
51 | while not rv and retry < 100:
52 | rv = _MoveFileEx(src, dst, _MOVEFILE_REPLACE_EXISTING |
53 | _MOVEFILE_WRITE_THROUGH)
54 | if not rv:
55 | time.sleep(0.001)
56 | retry += 1
57 | return rv
58 |
59 | # new in Vista and Windows Server 2008
60 | _CreateTransaction = ctypes.windll.ktmw32.CreateTransaction
61 | _CommitTransaction = ctypes.windll.ktmw32.CommitTransaction
62 | _MoveFileTransacted = ctypes.windll.kernel32.MoveFileTransactedW
63 | _CloseHandle = ctypes.windll.kernel32.CloseHandle
64 | can_rename_open_file = True
65 |
66 | def _rename_atomic(src, dst):
67 | ta = _CreateTransaction(None, 0, 0, 0, 0, 1000, 'Werkzeug rename')
68 | if ta == -1:
69 | return False
70 | try:
71 | retry = 0
72 | rv = False
73 | while not rv and retry < 100:
74 | rv = _MoveFileTransacted(src, dst, None, None,
75 | _MOVEFILE_REPLACE_EXISTING |
76 | _MOVEFILE_WRITE_THROUGH, ta)
77 | if rv:
78 | rv = _CommitTransaction(ta)
79 | break
80 | else:
81 | time.sleep(0.001)
82 | retry += 1
83 | return rv
84 | finally:
85 | _CloseHandle(ta)
86 | except Exception:
87 | pass
88 |
89 | def rename(src, dst):
90 | # Try atomic or pseudo-atomic rename
91 | if _rename(src, dst):
92 | return
93 | # Fall back to "move away and replace"
94 | try:
95 | shutil.move(src, dst)
96 | except OSError as e:
97 | if e.errno != errno.EEXIST:
98 | raise
99 | old = "%s-%08x" % (dst, random.randint(0, sys.maxint))
100 | shutil.move(dst, old)
101 | shutil.move(src, dst)
102 | try:
103 | os.unlink(old)
104 | except Exception:
105 | pass
106 | else:
107 | """
108 | If dst on current filesystem then use
109 | atomic rename. Otherwise, fall back to a
110 | non-atomic copy and remove.
111 | """
112 | rename = shutil.move
113 | can_rename_open_file = True
114 |
--------------------------------------------------------------------------------
/pokepy/resources_v2.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 | """
5 | Resources related to the V2 API
6 |
7 | Refer to the documentation for more information
8 | (https://pokeapi.co/docs/v2.html)
9 | """
10 |
11 | from beckett.resources import BaseResource as OriginalBaseResource
12 | from beckett.resources import SubResource
13 |
14 |
15 | class BaseResource(OriginalBaseResource):
16 | """
17 | Fix for "type object argument after ** must be a mapping, not NoneType"
18 | """
19 | def set_subresources(self, **kwargs):
20 | """Same logic as the original except for the first 'if' clause."""
21 | for attribute_name, resource in self._subresource_map.items():
22 | sub_attr = kwargs.get(attribute_name)
23 | if sub_attr is None:
24 | # Attribute was not found or is null
25 | value = None
26 | elif isinstance(sub_attr, list):
27 | # A list of subresources is supported
28 | value = [resource(**x) for x in sub_attr]
29 | else:
30 | # So is a single resource
31 | value = resource(**sub_attr)
32 | setattr(self, attribute_name, value)
33 |
34 |
35 | ##############################
36 | # Common Models (SubResources)
37 | ##############################
38 |
39 |
40 | class APIResourceSubResource(SubResource):
41 | class Meta:
42 | name = 'API_Resource'
43 | identifier = 'url'
44 | attributes = (
45 | 'url',
46 | )
47 |
48 | def __repr__(self):
49 | return '<%s - %s>' % (self.Meta.name, self.url)
50 |
51 |
52 | class NamedAPIResourceSubResource(SubResource):
53 | class Meta:
54 | name = 'Named_API_Resource'
55 | identifier = 'name'
56 | attributes = (
57 | 'name',
58 | 'url'
59 | )
60 |
61 | def __repr__(self):
62 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
63 |
64 |
65 | class DescriptionSubResource(BaseResource):
66 | class Meta(BaseResource.Meta):
67 | name = 'Description'
68 | identifier = 'description'
69 | attributes = (
70 | 'description',
71 | )
72 | subresources = {
73 | 'language': NamedAPIResourceSubResource
74 | }
75 |
76 | def __repr__(self):
77 | return '<%s - %s>' % (self.Meta.name,
78 | self.description.capitalize()[:10] + "...")
79 |
80 |
81 | class EffectSubResource(BaseResource):
82 | class Meta(BaseResource.Meta):
83 | name = 'Effect'
84 | identifier = 'effect'
85 | attributes = (
86 | 'effect',
87 | )
88 | subresources = {
89 | 'language': NamedAPIResourceSubResource
90 | }
91 |
92 | def __repr__(self):
93 | return '<%s - %s>' % (self.Meta.name,
94 | self.effect.capitalize()[:10] + "...")
95 |
96 |
97 | class EncounterSubResource(BaseResource):
98 | class Meta(BaseResource.Meta):
99 | name = 'Encounter'
100 | identifier = 'chance'
101 | attributes = (
102 | 'min_level',
103 | 'max_level',
104 | 'chance'
105 | )
106 | subresources = {
107 | 'condition_values': NamedAPIResourceSubResource,
108 | 'method': NamedAPIResourceSubResource
109 | }
110 |
111 | def __repr__(self):
112 | return '<%s - %s/%s/%s>' % (self.Meta.name, self.min_level,
113 | self.max_level, self.chance)
114 |
115 |
116 | class FlavorTextSubResource(BaseResource):
117 | class Meta(BaseResource.Meta):
118 | name = 'Flavor_Text'
119 | identifier = 'flavor_text'
120 | attributes = (
121 | 'flavor_text',
122 | )
123 | subresources = {
124 | 'language': NamedAPIResourceSubResource,
125 | 'version': NamedAPIResourceSubResource
126 | }
127 |
128 | def __repr__(self):
129 | return '<%s - %s>' % (self.Meta.name,
130 | self.flavor_text.capitalize()[:10] + "...")
131 |
132 |
133 | class GenerationGameIndexSubResource(BaseResource):
134 | class Meta(BaseResource.Meta):
135 | name = 'Generation_Game_Index'
136 | identifier = 'game_index'
137 | attributes = (
138 | 'game_index',
139 | )
140 | subresources = {
141 | 'generation': NamedAPIResourceSubResource
142 | }
143 |
144 | def __repr__(self):
145 | return '<%s - %s>' % (self.Meta.name, self.game_index)
146 |
147 |
148 | class MachineVersionDetailSubResource(BaseResource):
149 | class Meta(BaseResource.Meta):
150 | name = 'Machine_Version_Detail'
151 | identifier = 'machine'
152 | subresources = {
153 | 'machine': APIResourceSubResource,
154 | 'version_group': NamedAPIResourceSubResource
155 | }
156 |
157 | def __repr__(self):
158 | return '<%s>' % self.Meta.name
159 |
160 |
161 | class NameSubResource(BaseResource):
162 | class Meta:
163 | name = 'Name'
164 | identifier = 'name'
165 | attributes = (
166 | 'name',
167 | )
168 | subresources = {
169 | 'language': NamedAPIResourceSubResource
170 | }
171 |
172 | def __repr__(self):
173 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
174 |
175 |
176 | class VerboseEffectSubResource(BaseResource):
177 | class Meta(BaseResource.Meta):
178 | name = 'Verbose_Effect'
179 | identifier = 'effect'
180 | attributes = (
181 | 'effect',
182 | 'short_effect'
183 | )
184 | subresources = {
185 | 'language': NamedAPIResourceSubResource
186 | }
187 |
188 | def __repr__(self):
189 | return '<%s - %s>' % (self.Meta.name, self.effect.capitalize())
190 |
191 |
192 | class VersionEncounterDetailSubResource(BaseResource):
193 | class Meta(BaseResource.Meta):
194 | name = 'Version_Encounter_Detail'
195 | identifier = 'max_chance'
196 | attributes = (
197 | 'max_chance',
198 | )
199 | subresources = {
200 | 'version': NamedAPIResourceSubResource,
201 | 'encounter_details': EncounterSubResource
202 | }
203 |
204 | def __repr__(self):
205 | return '<%s - %s>' % (self.Meta.name, self.max_chance)
206 |
207 |
208 | class VersionGameIndexSubResource(BaseResource):
209 | class Meta(BaseResource.Meta):
210 | name = 'Version_Game_Index'
211 | identifier = 'game_index'
212 | attributes = (
213 | 'game_index',
214 | )
215 | subresources = {
216 | 'version': NamedAPIResourceSubResource
217 | }
218 |
219 | def __repr__(self):
220 | return '<%s - %s>' % (self.Meta.name, self.game_index)
221 |
222 |
223 | class VersionGroupFlavorTextSubResource(BaseResource):
224 | class Meta(BaseResource.Meta):
225 | name = 'Version_Group_Flavor_Text'
226 | identifier = 'text'
227 | attributes = (
228 | 'text',
229 | )
230 | subresources = {
231 | 'language': NamedAPIResourceSubResource,
232 | 'version_group': NamedAPIResourceSubResource
233 | }
234 |
235 | def __repr__(self):
236 | return '<%s - %s>' % (self.Meta.name,
237 | self.text.capitalize()[:10] + "...")
238 |
239 |
240 | ##############
241 | # SubResources
242 | ##############
243 |
244 |
245 | class BerryFlavorMapSubResource(BaseResource):
246 | class Meta(BaseResource.Meta):
247 | name = 'Berry_Flavor_Map'
248 | identifier = 'potency'
249 | attributes = (
250 | 'potency',
251 | )
252 | subresources = {
253 | 'flavor': NamedAPIResourceSubResource
254 | }
255 |
256 | def __repr__(self):
257 | return '<%s - %s>' % (self.Meta.name, self.potency)
258 |
259 |
260 | class FlavorBerryMapSubResource(BaseResource):
261 | class Meta(BaseResource.Meta):
262 | name = 'Flavor_Berry_Map'
263 | identifier = 'potency'
264 | attributes = (
265 | 'potency',
266 | )
267 | subresources = {
268 | 'berry': NamedAPIResourceSubResource
269 | }
270 |
271 | def __repr__(self):
272 | return '<%s - %s>' % (self.Meta.name, self.potency)
273 |
274 |
275 | class ContestNameSubResource(BaseResource):
276 | class Meta(BaseResource.Meta):
277 | name = 'Contest_Name'
278 | identifier = 'name'
279 | attributes = (
280 | 'name',
281 | 'color'
282 | )
283 | subresources = {
284 | 'language': NamedAPIResourceSubResource
285 | }
286 |
287 | def __repr__(self):
288 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
289 |
290 |
291 | class EvolutionDetailSubResource(BaseResource):
292 | class Meta(BaseResource.Meta):
293 | name = 'Evolution_Detail'
294 | identifier = 'gender'
295 | attributes = (
296 | 'gender',
297 | 'min_level',
298 | 'min_happiness',
299 | 'min_beauty',
300 | 'min_affection',
301 | 'needs_overworld_rain',
302 | 'relative_physical_stats',
303 | 'time_of_day',
304 | 'turn_upside_down'
305 | )
306 | subresources = {
307 | 'item': NamedAPIResourceSubResource,
308 | 'trigger': NamedAPIResourceSubResource,
309 | 'held_item': NamedAPIResourceSubResource,
310 | 'known_move': NamedAPIResourceSubResource,
311 | 'known_move_type': NamedAPIResourceSubResource,
312 | 'location': NamedAPIResourceSubResource,
313 | 'party_species': NamedAPIResourceSubResource,
314 | 'party_type': NamedAPIResourceSubResource,
315 | 'trade_species': NamedAPIResourceSubResource
316 | }
317 |
318 | def __repr__(self):
319 | return '<%s>' % self.Meta.name
320 |
321 |
322 | # A ChainLink is tricky to implement with beckett because it is recursive.
323 | # The current solution is to have 3 nearly identical ChainLink classes
324 | # (so far, the maximum number of chaining evolutions depth is 3)
325 | # the last one not having the evolves_to subresource, ending the recursion.
326 |
327 |
328 | class ChainLink2SubResource(BaseResource):
329 | class Meta(BaseResource.Meta):
330 | name = 'Chain_Link2'
331 | identifier = 'is_baby'
332 | attributes = (
333 | 'is_baby',
334 | )
335 | subresources = {
336 | 'species': NamedAPIResourceSubResource,
337 | 'evolution_details': EvolutionDetailSubResource
338 | }
339 |
340 | def __repr__(self):
341 | return '<%s>' % self.Meta.name
342 |
343 |
344 | class ChainLink1SubResource(BaseResource):
345 | class Meta(BaseResource.Meta):
346 | name = 'Chain_Link1'
347 | identifier = 'is_baby'
348 | attributes = (
349 | 'is_baby',
350 | )
351 | subresources = {
352 | 'species': NamedAPIResourceSubResource,
353 | 'evolution_details': EvolutionDetailSubResource,
354 | 'evolves_to': ChainLink2SubResource
355 | }
356 |
357 | def __repr__(self):
358 | return '<%s>' % self.Meta.name
359 |
360 |
361 | class ChainLinkSubResource(BaseResource):
362 | class Meta(BaseResource.Meta):
363 | name = 'Chain_Link'
364 | identifier = 'is_baby'
365 | attributes = (
366 | 'is_baby',
367 | )
368 | subresources = {
369 | 'species': NamedAPIResourceSubResource,
370 | 'evolution_details': EvolutionDetailSubResource,
371 | 'evolves_to': ChainLink1SubResource
372 | }
373 |
374 | def __repr__(self):
375 | return '<%s>' % self.Meta.name
376 |
377 |
378 | class PokemonEntrySubResource(BaseResource):
379 | class Meta(BaseResource.Meta):
380 | name = 'Pokemon_Entry'
381 | identifier = 'entry_number'
382 | attributes = (
383 | 'entry_number',
384 | )
385 | subresources = {
386 | 'pokemon_species': NamedAPIResourceSubResource
387 | }
388 |
389 | def __repr__(self):
390 | return '<%s - %s>' % (self.Meta.name, self.entry_number)
391 |
392 |
393 | class ItemSpritesSubResource(SubResource):
394 | class Meta(BaseResource.Meta):
395 | name = 'Item_Sprites'
396 | identifier = 'default'
397 | attributes = (
398 | 'default',
399 | )
400 |
401 | def __repr__(self):
402 | return '<%s - %s>' % (self.Meta.name,
403 | self.default.capitalize()[:10] + "...")
404 |
405 |
406 | class ItemHolderPokemonVersionDetailSubResource(BaseResource):
407 | class Meta(BaseResource.Meta):
408 | name = 'Item_Holder_Pokemon_Version_Detail'
409 | identifier = 'rarity'
410 | attributes = (
411 | 'rarity',
412 | )
413 | subresources = {
414 | 'version': NamedAPIResourceSubResource
415 | }
416 |
417 | def __repr__(self):
418 | return '<%s>' % self.Meta.name
419 |
420 |
421 | class ItemHolderPokemonSubResource(BaseResource):
422 | class Meta(BaseResource.Meta):
423 | name = 'Item_Holder_Pokemon'
424 | identifier = 'pokemon'
425 | subresources = {
426 | 'pokemon': NamedAPIResourceSubResource,
427 | 'version_details': ItemHolderPokemonVersionDetailSubResource
428 | }
429 |
430 | def __repr__(self):
431 | return '<%s>' % self.Meta.name
432 |
433 |
434 | class ContestComboDetailSubResource(BaseResource):
435 | class Meta(BaseResource.Meta):
436 | name = 'Contest_Combo_Detail'
437 | identifier = 'use_before'
438 | subresources = {
439 | 'use_before': NamedAPIResourceSubResource,
440 | 'use_after': NamedAPIResourceSubResource
441 | }
442 |
443 | def __repr__(self):
444 | return '<%s>' % self.Meta.name
445 |
446 |
447 | class ContestComboSetsSubResource(BaseResource):
448 | class Meta(BaseResource.Meta):
449 | name = 'Contest_Combo_Sets'
450 | identifier = 'normal'
451 | subresources = {
452 | 'normal': ContestComboDetailSubResource,
453 | 'super': ContestComboDetailSubResource
454 | }
455 |
456 | def __repr__(self):
457 | return '<%s>' % self.Meta.name
458 |
459 |
460 | class MoveFlavorTextSubResource(BaseResource):
461 | class Meta(BaseResource.Meta):
462 | name = 'Move_Flavor_Text'
463 | identifier = 'flavor_text'
464 | attributes = (
465 | 'flavor_text',
466 | )
467 | subresources = {
468 | 'language': NamedAPIResourceSubResource,
469 | 'version_group': NamedAPIResourceSubResource
470 | }
471 |
472 | def __repr__(self):
473 | return '<%s - %s>' % (self.Meta.name,
474 | self.flavor_text.capitalize()[:10] + "...")
475 |
476 |
477 | class MoveMetaDataSubResource(BaseResource):
478 | class Meta(BaseResource.Meta):
479 | name = 'Move_Meta_Data'
480 | identifier = 'min_hits'
481 | attributes = (
482 | 'min_hits',
483 | 'max_hits',
484 | 'min_turns',
485 | 'max_turns',
486 | 'drain',
487 | 'healing',
488 | 'crit_rate',
489 | 'ailment_chance',
490 | 'flinch_chance',
491 | 'stat_chance'
492 | )
493 | subresources = {
494 | 'ailment': NamedAPIResourceSubResource,
495 | 'category': NamedAPIResourceSubResource
496 | }
497 |
498 | def __repr__(self):
499 | return '<%s>' % self.Meta.name
500 |
501 |
502 | class MoveStatChangeSubResource(BaseResource):
503 | class Meta(BaseResource.Meta):
504 | name = 'Move_Stat_Change'
505 | identifier = 'change'
506 | attributes = (
507 | 'change',
508 | )
509 | subresources = {
510 | 'stat': NamedAPIResourceSubResource
511 | }
512 |
513 | def __repr__(self):
514 | return '<%s - %s>' % (self.Meta.name, self.change)
515 |
516 |
517 | class PastMoveStatValuesSubResource(BaseResource):
518 | class Meta(BaseResource.Meta):
519 | name = 'Past_Move_Stat_Values'
520 | identifier = 'accuracy'
521 | attributes = (
522 | 'accuracy',
523 | 'effect_chance',
524 | 'power',
525 | 'pp'
526 | )
527 | subresources = {
528 | 'effect_entries': VerboseEffectSubResource,
529 | 'type': NamedAPIResourceSubResource,
530 | 'version_group': NamedAPIResourceSubResource
531 | }
532 |
533 | def __repr__(self):
534 | return '<%s>' % self.Meta.name
535 |
536 |
537 | class EncounterVersionDetailsSubResource(BaseResource):
538 | class Meta(BaseResource.Meta):
539 | name = 'Encounter_Version_Details'
540 | identifier = 'rate'
541 | attributes = (
542 | 'rate',
543 | )
544 | subresources = {
545 | 'version': NamedAPIResourceSubResource
546 | }
547 |
548 | def __repr__(self):
549 | return '<%s - %s>' % (self.Meta.name, self.rate)
550 |
551 |
552 | class EncounterMethodRateSubResource(BaseResource):
553 | class Meta(BaseResource.Meta):
554 | name = 'Encounter_Method_Rate'
555 | identifier = 'encounter_method'
556 | subresources = {
557 | 'encounter_method': NamedAPIResourceSubResource,
558 | 'version_details': EncounterVersionDetailsSubResource
559 | }
560 |
561 | def __repr__(self):
562 | return '<%s>' % self.Meta.name
563 |
564 |
565 | class PokemonEncounterSubResource(BaseResource):
566 | class Meta(BaseResource.Meta):
567 | name = 'Pokemon_Encounter'
568 | identifier = 'pokemon'
569 | subresources = {
570 | 'pokemon': NamedAPIResourceSubResource,
571 | 'version_details': VersionEncounterDetailSubResource
572 | }
573 |
574 | def __repr__(self):
575 | return '<%s>' % self.Meta.name
576 |
577 |
578 | class PalParkEncounterSpeciesSubResource(BaseResource):
579 | class Meta(BaseResource.Meta):
580 | name = 'Pal_Park_Encounter_Species'
581 | identifier = 'rate'
582 | attributes = (
583 | 'base_score',
584 | 'rate'
585 | )
586 | subresources = {
587 | 'pokemon_species': NamedAPIResourceSubResource
588 | }
589 |
590 | def __repr__(self):
591 | return '<%s>' % self.Meta.name
592 |
593 |
594 | class AbilityEffectChangeSubResource(BaseResource):
595 | class Meta(BaseResource.Meta):
596 | name = 'Ability_Effect_Change'
597 | identifier = 'effect_entries'
598 | subresources = {
599 | 'effect_entries': EffectSubResource,
600 | 'version_group': NamedAPIResourceSubResource
601 | }
602 |
603 | def __repr__(self):
604 | return '<%s>' % self.Meta.name
605 |
606 |
607 | class AbilityFlavorTextSubResource(BaseResource):
608 | class Meta(BaseResource.Meta):
609 | name = 'Ability_Flavor_Text'
610 | identifier = 'flavor_text'
611 | attributes = (
612 | 'flavor_text',
613 | )
614 | subresources = {
615 | 'language': NamedAPIResourceSubResource,
616 | 'version_group': NamedAPIResourceSubResource
617 | }
618 |
619 | def __repr__(self):
620 | return '<%s - %s>' % (self.Meta.name,
621 | self.flavor_text.capitalize()[:10] + "...")
622 |
623 |
624 | class AbilityPokemonSubResource(BaseResource):
625 | class Meta(BaseResource.Meta):
626 | name = 'Ability_Pokemon'
627 | identifier = 'slot'
628 | attributes = (
629 | 'is_hidden',
630 | 'slot'
631 | )
632 | subresources = {
633 | 'pokemon': NamedAPIResourceSubResource
634 | }
635 |
636 | def __repr__(self):
637 | return '<%s>' % self.Meta.name
638 |
639 |
640 | class PokemonSpeciesGenderSubResource(BaseResource):
641 | class Meta(BaseResource.Meta):
642 | name = 'Pokemon_Species_Gender'
643 | identifier = 'rate'
644 | attributes = (
645 | 'rate',
646 | )
647 | subresources = {
648 | 'pokemon_species': NamedAPIResourceSubResource
649 | }
650 |
651 | def __repr__(self):
652 | return '<%s - %s>' % (self.Meta.name, self.rate)
653 |
654 |
655 | class GrowthRateExperienceLevelSubResource(SubResource):
656 | class Meta(BaseResource.Meta):
657 | name = 'Growth_Rate_Experience_Level'
658 | identifier = 'level'
659 | attributes = (
660 | 'level',
661 | 'experience'
662 | )
663 |
664 | def __repr__(self):
665 | return '<%s - %s/%s>' % (self.Meta.name, self.level, self.experience)
666 |
667 |
668 | class NatureStatChangeSubResource(BaseResource):
669 | class Meta(BaseResource.Meta):
670 | name = 'Nature_Stat_Change'
671 | identifier = 'max_change'
672 | attributes = (
673 | 'max_change',
674 | )
675 | subresources = {
676 | 'pokeathlon_stat': NamedAPIResourceSubResource
677 | }
678 |
679 | def __repr__(self):
680 | return '<%s - %s>' % (self.Meta.name, self.max_change)
681 |
682 |
683 | class MoveBattleStylePreferenceSubResource(BaseResource):
684 | class Meta(BaseResource.Meta):
685 | name = 'Move_Battle_Style_Preference'
686 | identifier = 'low_hp_preference'
687 | attributes = (
688 | 'low_hp_preference',
689 | 'high_hp_preference'
690 | )
691 | subresources = {
692 | 'move_battle_style': NamedAPIResourceSubResource
693 | }
694 |
695 | def __repr__(self):
696 | return '<%s - %s/%s>' % (self.Meta.name, self.low_hp_preference,
697 | self.high_hp_preference)
698 |
699 |
700 | class NaturePokeathlonStatAffectSubResource(BaseResource):
701 | class Meta(BaseResource.Meta):
702 | name = 'Nature_Pokeathlon_Stat_Affect'
703 | identifier = 'max_change'
704 | attributes = (
705 | 'max_change',
706 | )
707 | subresources = {
708 | 'nature': NamedAPIResourceSubResource
709 | }
710 |
711 | def __repr__(self):
712 | return '<%s - %s>' % (self.Meta.name, self.max_change)
713 |
714 |
715 | class NaturePokeathlonStatAffectSetsSubResource(BaseResource):
716 | class Meta(BaseResource.Meta):
717 | name = 'Nature_Pokeathlon_Stat_Affect_Sets'
718 | identifier = 'increase'
719 | subresources = {
720 | 'increase': NaturePokeathlonStatAffectSubResource,
721 | 'decrease': NaturePokeathlonStatAffectSubResource
722 | }
723 |
724 | def __repr__(self):
725 | return '<%s>' % self.Meta.name
726 |
727 |
728 | class PokemonAbilitySubResource(BaseResource):
729 | class Meta(BaseResource.Meta):
730 | name = 'Pokemon_Ability'
731 | identifier = 'is_hidden'
732 | attributes = (
733 | 'is_hidden',
734 | 'slot'
735 | )
736 | subresources = {
737 | 'ability': NamedAPIResourceSubResource
738 | }
739 |
740 | def __repr__(self):
741 | return '<%s>' % self.Meta.name
742 |
743 |
744 | class PokemonTypeSubResource(BaseResource):
745 | class Meta(BaseResource.Meta):
746 | name = 'Pokemon_Type'
747 | identifier = 'slot'
748 | attributes = (
749 | 'slot',
750 | )
751 | subresources = {
752 | 'type': NamedAPIResourceSubResource
753 | }
754 |
755 | def __repr__(self):
756 | return '<%s>' % self.Meta.name
757 |
758 |
759 | class PokemonHeldItemVersionSubResource(BaseResource):
760 | class Meta(BaseResource.Meta):
761 | name = 'Pokemon_Held_Item_Version'
762 | identifier = 'rarity'
763 | attributes = (
764 | 'rarity',
765 | )
766 | subresources = {
767 | 'version': NamedAPIResourceSubResource
768 | }
769 |
770 | def __repr__(self):
771 | return '<%s>' % self.Meta.name
772 |
773 |
774 | class PokemonHeldItemSubResource(BaseResource):
775 | class Meta(BaseResource.Meta):
776 | name = 'Pokemon_Held_Item'
777 | identifier = 'item'
778 | subresources = {
779 | 'item': NamedAPIResourceSubResource,
780 | 'version_details': PokemonHeldItemVersionSubResource
781 | }
782 |
783 | def __repr__(self):
784 | return '<%s>' % self.Meta.name
785 |
786 |
787 | class PokemonMoveVersionSubResource(BaseResource):
788 | class Meta(BaseResource.Meta):
789 | name = 'Pokemon_Move_Version'
790 | identifier = 'level_learned_at'
791 | attributes = (
792 | 'level_learned_at',
793 | )
794 | subresources = {
795 | 'move_learn_method': NamedAPIResourceSubResource,
796 | 'version_group': NamedAPIResourceSubResource
797 | }
798 |
799 | def __repr__(self):
800 | return '<%s>' % self.Meta.name
801 |
802 |
803 | class PokemonMoveSubResource(BaseResource):
804 | class Meta(BaseResource.Meta):
805 | name = 'Pokemon_Move'
806 | identifier = 'move'
807 | subresources = {
808 | 'move': NamedAPIResourceSubResource,
809 | 'version_group_details': PokemonMoveVersionSubResource
810 | }
811 |
812 | def __repr__(self):
813 | return '<%s>' % self.Meta.name
814 |
815 |
816 | class PokemonStatSubResource(BaseResource):
817 | class Meta(BaseResource.Meta):
818 | name = 'Pokemon_Stat'
819 | identifier = 'effort'
820 | attributes = (
821 | 'effort',
822 | 'base_stat'
823 | )
824 | subresources = {
825 | 'stat': NamedAPIResourceSubResource
826 | }
827 |
828 | def __repr__(self):
829 | return '<%s>' % self.Meta.name
830 |
831 |
832 | class PokemonSpritesSubResource(SubResource):
833 | class Meta(BaseResource.Meta):
834 | name = 'Pokemon_Sprites'
835 | identifier = 'front_default'
836 | attributes = (
837 | 'front_default',
838 | 'front_shiny',
839 | 'front_female',
840 | 'front_shiny_female',
841 | 'back_default',
842 | 'back_shiny',
843 | 'back_female',
844 | 'back_shiny_female',
845 | )
846 |
847 | def __repr__(self):
848 | return '<%s>' % self.Meta.name
849 |
850 |
851 | class LocationAreaEncounterSubResource(BaseResource):
852 | class Meta(BaseResource.Meta):
853 | name = 'Location_Area_Encounter'
854 | identifier = 'location_area'
855 | subresources = {
856 | 'location_area': NamedAPIResourceSubResource,
857 | 'version_details': VersionEncounterDetailSubResource
858 | }
859 |
860 | def __repr__(self):
861 | return '<%s>' % self.Meta.name
862 |
863 |
864 | class PokemonFormSpritesSubResource(SubResource):
865 | class Meta(BaseResource.Meta):
866 | name = 'Pokemon_Form_Sprites'
867 | identifier = 'front_default'
868 | attributes = (
869 | 'front_default',
870 | 'front_shiny',
871 | 'back_default',
872 | 'back_shiny'
873 | )
874 |
875 | def __repr__(self):
876 | return '<%s>' % self.Meta.name
877 |
878 |
879 | class AwesomeNameSubResource(BaseResource):
880 | class Meta(BaseResource.Meta):
881 | name = 'Awesome_Name'
882 | identifier = 'awesome_name'
883 | attributes = (
884 | 'awesome_name',
885 | )
886 | subresources = {
887 | 'language': NamedAPIResourceSubResource
888 | }
889 |
890 | def __repr__(self):
891 | return '<%s - %s>' % (self.Meta.name, self.awesome_name.capitalize())
892 |
893 |
894 | class GenusSubResource(BaseResource):
895 | class Meta(BaseResource.Meta):
896 | name = 'Genus'
897 | identifier = 'genus'
898 | attributes = (
899 | 'genus',
900 | )
901 | subresources = {
902 | 'language': NamedAPIResourceSubResource
903 | }
904 |
905 | def __repr__(self):
906 | return '<%s - %s>' % (self.Meta.name, self.genus.capitalize())
907 |
908 |
909 | class PokemonSpeciesDexEntrySubResource(BaseResource):
910 | class Meta(BaseResource.Meta):
911 | name = 'Pokemon_Species_Dex_Entry'
912 | identifier = 'entry_number'
913 | attributes = (
914 | 'entry_number',
915 | )
916 | subresources = {
917 | 'pokedex': NamedAPIResourceSubResource
918 | }
919 |
920 | def __repr__(self):
921 | return '<%s - %s>' % (self.Meta.name, self.entry_number)
922 |
923 |
924 | class PalParkEncounterAreaSubResource(BaseResource):
925 | class Meta(BaseResource.Meta):
926 | name = 'Pal_Park_Encounter_Area'
927 | identifier = 'base_score'
928 | attributes = (
929 | 'base_score',
930 | 'rate'
931 | )
932 | subresources = {
933 | 'area': NamedAPIResourceSubResource
934 | }
935 |
936 | def __repr__(self):
937 | return '<%s>' % self.Meta.name
938 |
939 |
940 | class PokemonSpeciesVarietySubResource(BaseResource):
941 | class Meta(BaseResource.Meta):
942 | name = 'Pokemon_Species_Variety'
943 | identifier = 'is_default'
944 | attributes = (
945 | 'is_default',
946 | )
947 | subresources = {
948 | 'pokemon': NamedAPIResourceSubResource
949 | }
950 |
951 | def __repr__(self):
952 | return '<%s>' % self.Meta.name
953 |
954 |
955 | class MoveStatAffectSubResource(BaseResource):
956 | class Meta(BaseResource.Meta):
957 | name = 'Move_Stat_Affect'
958 | identifier = 'change'
959 | attributes = (
960 | 'change',
961 | )
962 | subresources = {
963 | 'move': NamedAPIResourceSubResource
964 | }
965 |
966 | def __repr__(self):
967 | return '<%s>' % self.Meta.name
968 |
969 |
970 | class MoveStatAffectSetsSubResource(BaseResource):
971 | class Meta(BaseResource.Meta):
972 | name = 'Move_Stat_Affect_Sets'
973 | identifier = 'increase'
974 | subresources = {
975 | 'increase': MoveStatAffectSubResource,
976 | 'decrease': MoveStatAffectSubResource
977 | }
978 |
979 | def __repr__(self):
980 | return '<%s>' % self.Meta.name
981 |
982 |
983 | class NatureStatAffectSetsSubResource(BaseResource):
984 | class Meta(BaseResource.Meta):
985 | name = 'Nature_Stat_Affect_Sets'
986 | identifier = 'increase'
987 | subresources = {
988 | 'increase': NamedAPIResourceSubResource,
989 | 'decrease': NamedAPIResourceSubResource
990 | }
991 |
992 | def __repr__(self):
993 | return '<%s>' % self.Meta.name
994 |
995 |
996 | class TypePokemonSubResource(BaseResource):
997 | class Meta(BaseResource.Meta):
998 | name = 'Type_Pokemon'
999 | identifier = 'slot'
1000 | attributes = (
1001 | 'slot',
1002 | )
1003 | subresources = {
1004 | 'pokemon': NamedAPIResourceSubResource
1005 | }
1006 |
1007 | def __repr__(self):
1008 | return '<%s>' % self.Meta.name
1009 |
1010 |
1011 | class TypeRelationsSubResource(BaseResource):
1012 | class Meta(BaseResource.Meta):
1013 | name = 'Type_Relations'
1014 | identifier = 'no_damage_to'
1015 | subresources = {
1016 | 'no_damage_to': NamedAPIResourceSubResource,
1017 | 'half_damage_to': NamedAPIResourceSubResource,
1018 | 'double_damage_to': NamedAPIResourceSubResource,
1019 | 'no_damage_from': NamedAPIResourceSubResource,
1020 | 'half_damage_from': NamedAPIResourceSubResource,
1021 | 'double_damage_from': NamedAPIResourceSubResource
1022 | }
1023 |
1024 | def __repr__(self):
1025 | return '<%s>' % self.Meta.name
1026 |
1027 |
1028 | ###########
1029 | # Resources
1030 | ###########
1031 |
1032 |
1033 | class BerryResource(BaseResource):
1034 |
1035 | class Meta(BaseResource.Meta):
1036 | name = 'Berry'
1037 | resource_name = 'berry'
1038 | identifier = 'id'
1039 | methods = (
1040 | 'get',
1041 | )
1042 | attributes = (
1043 | 'id',
1044 | 'name',
1045 | 'growth_time',
1046 | 'max_harvest',
1047 | 'natural_gift_power',
1048 | 'size',
1049 | 'smoothness',
1050 | 'soil_dryness'
1051 | )
1052 | subresources = {
1053 | 'firmness': NamedAPIResourceSubResource,
1054 | 'flavors': BerryFlavorMapSubResource,
1055 | 'item': NamedAPIResourceSubResource,
1056 | 'natural_gift_type': NamedAPIResourceSubResource
1057 | }
1058 |
1059 | def __repr__(self):
1060 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1061 |
1062 |
1063 | class BerryFirmnessResource(BaseResource):
1064 |
1065 | class Meta(BaseResource.Meta):
1066 | name = 'Berry_Firmness'
1067 | resource_name = 'berry-firmness'
1068 | identifier = 'id'
1069 | methods = (
1070 | 'get',
1071 | )
1072 | attributes = (
1073 | 'id',
1074 | 'name'
1075 | )
1076 | subresources = {
1077 | 'berries': NamedAPIResourceSubResource,
1078 | 'names': NameSubResource
1079 | }
1080 |
1081 | def __repr__(self):
1082 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1083 |
1084 |
1085 | class BerryFlavorResource(BaseResource):
1086 |
1087 | class Meta(BaseResource.Meta):
1088 | name = 'Berry_Flavor'
1089 | resource_name = 'berry-flavor'
1090 | identifier = 'id'
1091 | methods = (
1092 | 'get',
1093 | )
1094 | attributes = (
1095 | 'id',
1096 | 'name'
1097 | )
1098 | subresources = {
1099 | 'berries': FlavorBerryMapSubResource,
1100 | 'contest_type': NamedAPIResourceSubResource,
1101 | 'names': NameSubResource
1102 | }
1103 |
1104 | def __repr__(self):
1105 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1106 |
1107 |
1108 | class ContestTypeResource(BaseResource):
1109 |
1110 | class Meta(BaseResource.Meta):
1111 | name = 'Contest_Type'
1112 | resource_name = 'contest-type'
1113 | identifier = 'id'
1114 | methods = (
1115 | 'get',
1116 | )
1117 | attributes = (
1118 | 'id',
1119 | 'name'
1120 | )
1121 | subresources = {
1122 | 'berry_flavor': NamedAPIResourceSubResource,
1123 | 'names': ContestNameSubResource
1124 | }
1125 |
1126 | def __repr__(self):
1127 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1128 |
1129 |
1130 | class ContestEffectResource(BaseResource):
1131 |
1132 | class Meta(BaseResource.Meta):
1133 | name = 'Contest_Effect'
1134 | resource_name = 'contest-effect'
1135 | identifier = 'id'
1136 | methods = (
1137 | 'get',
1138 | )
1139 | attributes = (
1140 | 'id',
1141 | 'appeal',
1142 | 'jam'
1143 | )
1144 | subresources = {
1145 | 'effect_entries': EffectSubResource,
1146 | 'flavor_text_entries': FlavorTextSubResource
1147 | }
1148 |
1149 | def __repr__(self):
1150 | return '<%s - %s>' % (self.Meta.name, self.id)
1151 |
1152 |
1153 | class SuperContestEffectResource(BaseResource):
1154 |
1155 | class Meta(BaseResource.Meta):
1156 | name = 'Super_Contest_Effect'
1157 | resource_name = 'super-contest-effect'
1158 | identifier = 'id'
1159 | methods = (
1160 | 'get',
1161 | )
1162 | attributes = (
1163 | 'id',
1164 | 'appeal'
1165 | )
1166 | subresources = {
1167 | 'flavor_text_entries': FlavorTextSubResource,
1168 | 'moves': NamedAPIResourceSubResource
1169 | }
1170 |
1171 | def __repr__(self):
1172 | return '<%s - %s>' % (self.Meta.name, self.id)
1173 |
1174 |
1175 | class EncounterMethodResource(BaseResource):
1176 |
1177 | class Meta(BaseResource.Meta):
1178 | name = 'Encounter_Method'
1179 | resource_name = 'encounter-method'
1180 | identifier = 'id'
1181 | methods = (
1182 | 'get',
1183 | )
1184 | attributes = (
1185 | 'id',
1186 | 'name',
1187 | 'order'
1188 | )
1189 | subresources = {
1190 | 'names': NameSubResource
1191 | }
1192 |
1193 | def __repr__(self):
1194 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1195 |
1196 |
1197 | class EncounterConditionResource(BaseResource):
1198 |
1199 | class Meta(BaseResource.Meta):
1200 | name = 'Encounter_Condition'
1201 | resource_name = 'encounter-condition'
1202 | identifier = 'id'
1203 | methods = (
1204 | 'get',
1205 | )
1206 | attributes = (
1207 | 'id',
1208 | 'name'
1209 | )
1210 | subresources = {
1211 | 'names': NameSubResource,
1212 | 'values': NamedAPIResourceSubResource
1213 | }
1214 |
1215 | def __repr__(self):
1216 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1217 |
1218 |
1219 | class EncounterConditionValueResource(BaseResource):
1220 |
1221 | class Meta(BaseResource.Meta):
1222 | name = 'Encounter_Condition_Value'
1223 | resource_name = 'encounter-condition-value'
1224 | identifier = 'id'
1225 | methods = (
1226 | 'get',
1227 | )
1228 | attributes = (
1229 | 'id',
1230 | 'name'
1231 | )
1232 | subresources = {
1233 | 'condition': NamedAPIResourceSubResource,
1234 | 'names': NameSubResource
1235 | }
1236 |
1237 | def __repr__(self):
1238 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1239 |
1240 |
1241 | class EvolutionChainResource(BaseResource):
1242 |
1243 | class Meta(BaseResource.Meta):
1244 | name = 'Evolution_Chain'
1245 | resource_name = 'evolution-chain'
1246 | identifier = 'id'
1247 | methods = (
1248 | 'get',
1249 | )
1250 | attributes = (
1251 | 'id',
1252 | )
1253 | subresources = {
1254 | 'baby_trigger_item': NamedAPIResourceSubResource,
1255 | 'chain': ChainLinkSubResource
1256 | }
1257 |
1258 | def __repr__(self):
1259 | return '<%s - %s>' % (self.Meta.name, self.id)
1260 |
1261 |
1262 | class EvolutionTriggerResource(BaseResource):
1263 |
1264 | class Meta(BaseResource.Meta):
1265 | name = 'Evolution_Trigger'
1266 | resource_name = 'evolution-trigger'
1267 | identifier = 'id'
1268 | methods = (
1269 | 'get',
1270 | )
1271 | attributes = (
1272 | 'id',
1273 | 'name'
1274 | )
1275 | subresources = {
1276 | 'names': NameSubResource,
1277 | 'pokemon_species': NamedAPIResourceSubResource
1278 | }
1279 |
1280 | def __repr__(self):
1281 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1282 |
1283 |
1284 | class GenerationResource(BaseResource):
1285 |
1286 | class Meta(BaseResource.Meta):
1287 | name = 'Generation'
1288 | resource_name = 'generation'
1289 | identifier = 'id'
1290 | methods = (
1291 | 'get',
1292 | )
1293 | attributes = (
1294 | 'id',
1295 | 'name'
1296 | )
1297 | subresources = {
1298 | 'abilities': NamedAPIResourceSubResource,
1299 | 'names': NameSubResource,
1300 | 'main_region': NamedAPIResourceSubResource,
1301 | 'moves': NamedAPIResourceSubResource,
1302 | 'pokemon_species': NamedAPIResourceSubResource,
1303 | 'types': NamedAPIResourceSubResource,
1304 | 'version_groups': NamedAPIResourceSubResource
1305 | }
1306 |
1307 | def __repr__(self):
1308 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1309 |
1310 |
1311 | class PokedexResource(BaseResource):
1312 |
1313 | class Meta(BaseResource.Meta):
1314 | name = 'Pokedex'
1315 | resource_name = 'pokedex'
1316 | identifier = 'id'
1317 | methods = (
1318 | 'get',
1319 | )
1320 | attributes = (
1321 | 'id',
1322 | 'name',
1323 | 'is_main_series'
1324 | )
1325 | subresources = {
1326 | 'descriptions': DescriptionSubResource,
1327 | 'names': NameSubResource,
1328 | 'pokemon_entries': PokemonEntrySubResource,
1329 | 'region': NamedAPIResourceSubResource,
1330 | 'version_groups': NamedAPIResourceSubResource
1331 | }
1332 |
1333 | def __repr__(self):
1334 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1335 |
1336 |
1337 | class VersionResource(BaseResource):
1338 |
1339 | class Meta(BaseResource.Meta):
1340 | name = 'Version'
1341 | resource_name = 'version'
1342 | identifier = 'id'
1343 | methods = (
1344 | 'get',
1345 | )
1346 | attributes = (
1347 | 'id',
1348 | 'name'
1349 | )
1350 | subresources = {
1351 | 'names': NameSubResource,
1352 | 'version_group': NamedAPIResourceSubResource
1353 | }
1354 |
1355 | def __repr__(self):
1356 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1357 |
1358 |
1359 | class VersionGroupResource(BaseResource):
1360 |
1361 | class Meta(BaseResource.Meta):
1362 | name = 'Version_Group'
1363 | resource_name = 'version-group'
1364 | identifier = 'id'
1365 | methods = (
1366 | 'get',
1367 | )
1368 | attributes = (
1369 | 'id',
1370 | 'name',
1371 | 'order'
1372 | )
1373 | subresources = {
1374 | 'generation': NamedAPIResourceSubResource,
1375 | 'move_learn_methods': NamedAPIResourceSubResource,
1376 | 'pokedexes': NamedAPIResourceSubResource,
1377 | 'regions': NamedAPIResourceSubResource,
1378 | 'versions': NamedAPIResourceSubResource
1379 | }
1380 |
1381 | def __repr__(self):
1382 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1383 |
1384 |
1385 | class ItemCategoryResource(BaseResource):
1386 |
1387 | class Meta(BaseResource.Meta):
1388 | name = 'Item_Category'
1389 | resource_name = 'item-category'
1390 | identifier = 'id'
1391 | methods = (
1392 | 'get',
1393 | )
1394 | attributes = (
1395 | 'id',
1396 | 'name'
1397 | )
1398 | subresources = {
1399 | 'items': NamedAPIResourceSubResource,
1400 | 'names': NameSubResource,
1401 | 'pocket': NamedAPIResourceSubResource
1402 | }
1403 |
1404 | def __repr__(self):
1405 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1406 |
1407 |
1408 | class ItemResource(BaseResource):
1409 |
1410 | class Meta(BaseResource.Meta):
1411 | name = 'Item'
1412 | resource_name = 'item'
1413 | identifier = 'id'
1414 | methods = (
1415 | 'get',
1416 | )
1417 | attributes = (
1418 | 'id',
1419 | 'name',
1420 | 'cost',
1421 | 'fling_power'
1422 | )
1423 | subresources = {
1424 | 'fling_effect': NamedAPIResourceSubResource,
1425 | 'attributes': NamedAPIResourceSubResource,
1426 | 'category': NamedAPIResourceSubResource,
1427 | 'effect_entries': VerboseEffectSubResource,
1428 | 'flavor_text_entries': VersionGroupFlavorTextSubResource,
1429 | 'game_indices': GenerationGameIndexSubResource,
1430 | 'names': NameSubResource,
1431 | 'sprites': ItemSpritesSubResource,
1432 | 'held_by_pokemon': ItemHolderPokemonSubResource,
1433 | 'baby_trigger_for': APIResourceSubResource,
1434 | 'machines': MachineVersionDetailSubResource
1435 | }
1436 |
1437 | def __repr__(self):
1438 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1439 |
1440 |
1441 | class ItemAttributeResource(BaseResource):
1442 |
1443 | class Meta(BaseResource.Meta):
1444 | name = 'Item_Attribute'
1445 | resource_name = 'item-attribute'
1446 | identifier = 'id'
1447 | methods = (
1448 | 'get',
1449 | )
1450 | attributes = (
1451 | 'id',
1452 | 'name'
1453 | )
1454 | subresources = {
1455 | 'items': NamedAPIResourceSubResource,
1456 | 'names': NameSubResource,
1457 | 'descriptions': DescriptionSubResource
1458 | }
1459 |
1460 | def __repr__(self):
1461 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1462 |
1463 |
1464 | class ItemFlingEffectResource(BaseResource):
1465 |
1466 | class Meta(BaseResource.Meta):
1467 | name = 'Item_Fling_Effect'
1468 | resource_name = 'item-fling-effect'
1469 | identifier = 'id'
1470 | methods = (
1471 | 'get',
1472 | )
1473 | attributes = (
1474 | 'id',
1475 | 'name'
1476 | )
1477 | subresources = {
1478 | 'effect_entries': EffectSubResource,
1479 | 'items': NamedAPIResourceSubResource
1480 | }
1481 |
1482 | def __repr__(self):
1483 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1484 |
1485 |
1486 | class ItemPocketResource(BaseResource):
1487 |
1488 | class Meta(BaseResource.Meta):
1489 | name = 'Item_Pocket'
1490 | resource_name = 'item-pocket'
1491 | identifier = 'id'
1492 | methods = (
1493 | 'get',
1494 | )
1495 | attributes = (
1496 | 'id',
1497 | 'name'
1498 | )
1499 | subresources = {
1500 | 'categories': NamedAPIResourceSubResource,
1501 | 'names': NameSubResource
1502 | }
1503 |
1504 | def __repr__(self):
1505 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1506 |
1507 |
1508 | class MachineResource(BaseResource):
1509 |
1510 | class Meta(BaseResource.Meta):
1511 | name = 'Machine'
1512 | resource_name = 'machine'
1513 | identifier = 'id'
1514 | methods = (
1515 | 'get',
1516 | )
1517 | attributes = (
1518 | 'id',
1519 | )
1520 | subresources = {
1521 | 'item': NamedAPIResourceSubResource,
1522 | 'move': NamedAPIResourceSubResource,
1523 | 'version_group': NamedAPIResourceSubResource
1524 | }
1525 |
1526 | def __repr__(self):
1527 | return '<%s - %s>' % (self.Meta.name, self.id)
1528 |
1529 |
1530 | class MoveResource(BaseResource):
1531 |
1532 | class Meta(BaseResource.Meta):
1533 | name = 'Move'
1534 | resource_name = 'move'
1535 | identifier = 'id'
1536 | methods = (
1537 | 'get',
1538 | )
1539 | attributes = (
1540 | 'id',
1541 | 'name',
1542 | 'accuracy',
1543 | 'effect_chance',
1544 | 'pp',
1545 | 'priority',
1546 | 'power'
1547 | )
1548 | subresources = {
1549 | 'contest_combos': ContestComboSetsSubResource,
1550 | 'contest_type': NamedAPIResourceSubResource,
1551 | 'contest_effect': APIResourceSubResource,
1552 | 'damage_class': NamedAPIResourceSubResource,
1553 | 'effect_entries': VerboseEffectSubResource,
1554 | 'effect_changes': AbilityEffectChangeSubResource,
1555 | 'learned_by_pokemon': NamedAPIResourceSubResource,
1556 | 'flavor_text_entries': MoveFlavorTextSubResource,
1557 | 'generation': NamedAPIResourceSubResource,
1558 | 'machines': MachineVersionDetailSubResource,
1559 | 'meta': MoveMetaDataSubResource,
1560 | 'names': NameSubResource,
1561 | 'past_values': PastMoveStatValuesSubResource,
1562 | 'stat_changes': MoveStatChangeSubResource,
1563 | 'super_contest_effect': APIResourceSubResource,
1564 | 'target': NamedAPIResourceSubResource,
1565 | 'type': NamedAPIResourceSubResource
1566 | }
1567 |
1568 | def __repr__(self):
1569 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1570 |
1571 |
1572 | class MoveAilmentResource(BaseResource):
1573 |
1574 | class Meta(BaseResource.Meta):
1575 | name = 'Move_Ailment'
1576 | resource_name = 'move-ailment'
1577 | identifier = 'id'
1578 | methods = (
1579 | 'get',
1580 | )
1581 | attributes = (
1582 | 'id',
1583 | 'name'
1584 | )
1585 | subresources = {
1586 | 'moves': NamedAPIResourceSubResource,
1587 | 'names': NameSubResource
1588 | }
1589 |
1590 | def __repr__(self):
1591 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1592 |
1593 |
1594 | class MoveBattleStyleResource(BaseResource):
1595 |
1596 | class Meta(BaseResource.Meta):
1597 | name = 'Move_Battle_Style'
1598 | resource_name = 'move-battle-style'
1599 | identifier = 'id'
1600 | methods = (
1601 | 'get',
1602 | )
1603 | attributes = (
1604 | 'id',
1605 | 'name'
1606 | )
1607 | subresources = {
1608 | 'names': NameSubResource
1609 | }
1610 |
1611 | def __repr__(self):
1612 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1613 |
1614 |
1615 | class MoveCategoryResource(BaseResource):
1616 |
1617 | class Meta(BaseResource.Meta):
1618 | name = 'Move_Category'
1619 | resource_name = 'move-category'
1620 | identifier = 'id'
1621 | methods = (
1622 | 'get',
1623 | )
1624 | attributes = (
1625 | 'id',
1626 | 'name'
1627 | )
1628 | subresources = {
1629 | 'moves': NamedAPIResourceSubResource,
1630 | 'descriptions': DescriptionSubResource
1631 | }
1632 |
1633 | def __repr__(self):
1634 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1635 |
1636 |
1637 | class MoveDamageClassResource(BaseResource):
1638 |
1639 | class Meta(BaseResource.Meta):
1640 | name = 'Move_Damage_Class'
1641 | resource_name = 'move-damage-class'
1642 | identifier = 'id'
1643 | methods = (
1644 | 'get',
1645 | )
1646 | attributes = (
1647 | 'id',
1648 | 'name'
1649 | )
1650 | subresources = {
1651 | 'descriptions': DescriptionSubResource,
1652 | 'moves': NamedAPIResourceSubResource,
1653 | 'names': NameSubResource
1654 | }
1655 |
1656 | def __repr__(self):
1657 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1658 |
1659 |
1660 | class MoveLearnMethodResource(BaseResource):
1661 |
1662 | class Meta(BaseResource.Meta):
1663 | name = 'Move_Learn_Method'
1664 | resource_name = 'move-learn-method'
1665 | identifier = 'id'
1666 | methods = (
1667 | 'get',
1668 | )
1669 | attributes = (
1670 | 'id',
1671 | 'name'
1672 | )
1673 | subresources = {
1674 | 'descriptions': DescriptionSubResource,
1675 | 'names': NameSubResource,
1676 | 'version_groups': NamedAPIResourceSubResource
1677 | }
1678 |
1679 | def __repr__(self):
1680 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1681 |
1682 |
1683 | class MoveTargetResource(BaseResource):
1684 |
1685 | class Meta(BaseResource.Meta):
1686 | name = 'Move_Target'
1687 | resource_name = 'move-target'
1688 | identifier = 'id'
1689 | methods = (
1690 | 'get',
1691 | )
1692 | attributes = (
1693 | 'id',
1694 | 'name'
1695 | )
1696 | subresources = {
1697 | 'descriptions': DescriptionSubResource,
1698 | 'moves': NamedAPIResourceSubResource,
1699 | 'names': NameSubResource
1700 | }
1701 |
1702 | def __repr__(self):
1703 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1704 |
1705 |
1706 | class LocationResource(BaseResource):
1707 |
1708 | class Meta(BaseResource.Meta):
1709 | name = 'Location'
1710 | resource_name = 'location'
1711 | identifier = 'id'
1712 | methods = (
1713 | 'get',
1714 | )
1715 | attributes = (
1716 | 'id',
1717 | 'name'
1718 | )
1719 | subresources = {
1720 | 'region': NamedAPIResourceSubResource,
1721 | 'names': NameSubResource,
1722 | 'game_indices': GenerationGameIndexSubResource,
1723 | 'areas': NamedAPIResourceSubResource
1724 | }
1725 |
1726 | def __repr__(self):
1727 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1728 |
1729 |
1730 | class LocationAreaResource(BaseResource):
1731 |
1732 | class Meta(BaseResource.Meta):
1733 | name = 'Location_Area'
1734 | resource_name = 'location-area'
1735 | identifier = 'id'
1736 | methods = (
1737 | 'get',
1738 | )
1739 | attributes = (
1740 | 'id',
1741 | 'name',
1742 | 'game_index'
1743 | )
1744 | subresources = {
1745 | 'encounter_method_rates': EncounterMethodRateSubResource,
1746 | 'location': NamedAPIResourceSubResource,
1747 | 'names': NameSubResource,
1748 | 'pokemon_encounters': PokemonEncounterSubResource
1749 | }
1750 |
1751 | def __repr__(self):
1752 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1753 |
1754 |
1755 | class PalParkAreaResource(BaseResource):
1756 |
1757 | class Meta(BaseResource.Meta):
1758 | name = 'Pal_Park_Area'
1759 | resource_name = 'pal-park-area'
1760 | identifier = 'id'
1761 | methods = (
1762 | 'get',
1763 | )
1764 | attributes = (
1765 | 'id',
1766 | 'name'
1767 | )
1768 | subresources = {
1769 | 'names': NameSubResource,
1770 | 'pokemon_encounters': PalParkEncounterSpeciesSubResource
1771 | }
1772 |
1773 | def __repr__(self):
1774 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1775 |
1776 |
1777 | class RegionResource(BaseResource):
1778 |
1779 | class Meta(BaseResource.Meta):
1780 | name = 'Region'
1781 | resource_name = 'region'
1782 | identifier = 'id'
1783 | methods = (
1784 | 'get',
1785 | )
1786 | attributes = (
1787 | 'id',
1788 | 'name'
1789 | )
1790 | subresources = {
1791 | 'locations': NamedAPIResourceSubResource,
1792 | 'main_generation': NamedAPIResourceSubResource,
1793 | 'names': NameSubResource,
1794 | 'pokedexes': NamedAPIResourceSubResource,
1795 | 'version_groups': NamedAPIResourceSubResource
1796 | }
1797 |
1798 | def __repr__(self):
1799 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1800 |
1801 |
1802 | class AbilityResource(BaseResource):
1803 |
1804 | class Meta(BaseResource.Meta):
1805 | name = 'Ability'
1806 | resource_name = 'ability'
1807 | identifier = 'id'
1808 | methods = (
1809 | 'get',
1810 | )
1811 | attributes = (
1812 | 'id',
1813 | 'name',
1814 | 'is_main_series'
1815 | )
1816 | subresources = {
1817 | 'generation': NamedAPIResourceSubResource,
1818 | 'names': NameSubResource,
1819 | 'effect_entries': VerboseEffectSubResource,
1820 | 'effect_changes': AbilityEffectChangeSubResource,
1821 | 'flavor_text_entries': AbilityFlavorTextSubResource,
1822 | 'pokemon': AbilityPokemonSubResource
1823 | }
1824 |
1825 | def __repr__(self):
1826 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1827 |
1828 |
1829 | class CharacteristicResource(BaseResource):
1830 |
1831 | class Meta(BaseResource.Meta):
1832 | name = 'Characteristic'
1833 | resource_name = 'characteristic'
1834 | identifier = 'id'
1835 | methods = (
1836 | 'get',
1837 | )
1838 | attributes = (
1839 | 'id',
1840 | 'gene_modulo',
1841 | 'possible_values'
1842 | )
1843 | subresources = {
1844 | 'descriptions': DescriptionSubResource
1845 | }
1846 |
1847 | def __repr__(self):
1848 | return '<%s - %s>' % (self.Meta.name, self.id)
1849 |
1850 |
1851 | class EggGroupResource(BaseResource):
1852 |
1853 | class Meta(BaseResource.Meta):
1854 | name = 'Egg_Group'
1855 | resource_name = 'egg-group'
1856 | identifier = 'id'
1857 | methods = (
1858 | 'get',
1859 | )
1860 | attributes = (
1861 | 'id',
1862 | 'name'
1863 | )
1864 | subresources = {
1865 | 'names': NameSubResource,
1866 | 'pokemon_species': NamedAPIResourceSubResource
1867 | }
1868 |
1869 | def __repr__(self):
1870 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1871 |
1872 |
1873 | class GenderResource(BaseResource):
1874 |
1875 | class Meta(BaseResource.Meta):
1876 | name = 'Gender'
1877 | resource_name = 'gender'
1878 | identifier = 'id'
1879 | methods = (
1880 | 'get',
1881 | )
1882 | attributes = (
1883 | 'id',
1884 | 'name'
1885 | )
1886 | subresources = {
1887 | 'pokemon_species_details': PokemonSpeciesGenderSubResource,
1888 | 'required_for_evolution': NamedAPIResourceSubResource
1889 | }
1890 |
1891 | def __repr__(self):
1892 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1893 |
1894 |
1895 | class GrowthRateResource(BaseResource):
1896 |
1897 | class Meta(BaseResource.Meta):
1898 | name = 'Growth_Rate'
1899 | resource_name = 'growth-rate'
1900 | identifier = 'id'
1901 | methods = (
1902 | 'get',
1903 | )
1904 | attributes = (
1905 | 'id',
1906 | 'name',
1907 | 'formula'
1908 | )
1909 | subresources = {
1910 | 'descriptions': DescriptionSubResource,
1911 | 'levels': GrowthRateExperienceLevelSubResource,
1912 | 'pokemon_species': NamedAPIResourceSubResource
1913 | }
1914 |
1915 | def __repr__(self):
1916 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1917 |
1918 |
1919 | class NatureResource(BaseResource):
1920 |
1921 | class Meta(BaseResource.Meta):
1922 | name = 'Nature'
1923 | resource_name = 'nature'
1924 | identifier = 'id'
1925 | methods = (
1926 | 'get',
1927 | )
1928 | attributes = (
1929 | 'id',
1930 | 'name',
1931 | )
1932 | subresources = {
1933 | 'decreased_stat': NamedAPIResourceSubResource,
1934 | 'increased_stat': NamedAPIResourceSubResource,
1935 | 'hates_flavor': NamedAPIResourceSubResource,
1936 | 'likes_flavor': NamedAPIResourceSubResource,
1937 | 'pokeathlon_stat_changes': NatureStatChangeSubResource,
1938 | 'move_battle_style_preferences': MoveBattleStylePreferenceSubResource,
1939 | 'names': NameSubResource
1940 | }
1941 |
1942 | def __repr__(self):
1943 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1944 |
1945 |
1946 | class PokeathlonStatResource(BaseResource):
1947 |
1948 | class Meta(BaseResource.Meta):
1949 | name = 'Pokeathlon_Stat'
1950 | resource_name = 'pokeathlon-stat'
1951 | identifier = 'id'
1952 | methods = (
1953 | 'get',
1954 | )
1955 | attributes = (
1956 | 'id',
1957 | 'name',
1958 | )
1959 | subresources = {
1960 | 'names': NameSubResource,
1961 | 'affecting_natures': NaturePokeathlonStatAffectSetsSubResource
1962 | }
1963 |
1964 | def __repr__(self):
1965 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
1966 |
1967 |
1968 | class PokemonResource(BaseResource):
1969 |
1970 | class Meta(BaseResource.Meta):
1971 | name = 'Pokemon'
1972 | resource_name = 'pokemon'
1973 | identifier = 'id'
1974 | methods = (
1975 | 'get',
1976 | )
1977 | attributes = (
1978 | 'id',
1979 | 'name',
1980 | 'base_experience',
1981 | 'height',
1982 | 'is_default',
1983 | 'order',
1984 | 'weight',
1985 | 'location_area_encounters'
1986 | )
1987 | subresources = {
1988 | 'abilities': PokemonAbilitySubResource,
1989 | 'forms': NamedAPIResourceSubResource,
1990 | 'game_indices': VersionGameIndexSubResource,
1991 | 'held_items': PokemonHeldItemSubResource,
1992 | 'moves': PokemonMoveSubResource,
1993 | 'sprites': PokemonSpritesSubResource,
1994 | 'species': NamedAPIResourceSubResource,
1995 | 'stats': PokemonStatSubResource,
1996 | 'types': PokemonTypeSubResource
1997 | }
1998 |
1999 | def __repr__(self):
2000 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
2001 |
2002 |
2003 | class PokemonColorResource(BaseResource):
2004 |
2005 | class Meta(BaseResource.Meta):
2006 | name = 'Pokemon_Color'
2007 | resource_name = 'pokemon-color'
2008 | identifier = 'id'
2009 | methods = (
2010 | 'get',
2011 | )
2012 | attributes = (
2013 | 'id',
2014 | 'name',
2015 | )
2016 | subresources = {
2017 | 'names': NameSubResource,
2018 | 'pokemon_species': NamedAPIResourceSubResource
2019 | }
2020 |
2021 | def __repr__(self):
2022 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
2023 |
2024 |
2025 | class PokemonFormResource(BaseResource):
2026 |
2027 | class Meta(BaseResource.Meta):
2028 | name = 'Pokemon_Form'
2029 | resource_name = 'pokemon-form'
2030 | identifier = 'id'
2031 | methods = (
2032 | 'get',
2033 | )
2034 | attributes = (
2035 | 'id',
2036 | 'name',
2037 | 'order',
2038 | 'form_order',
2039 | 'is_default',
2040 | 'is_battle_only',
2041 | 'is_mega',
2042 | 'form_name',
2043 | )
2044 | subresources = {
2045 | 'pokemon': NamedAPIResourceSubResource,
2046 | 'sprites': PokemonFormSpritesSubResource,
2047 | 'version_group': NamedAPIResourceSubResource,
2048 | 'names': NameSubResource,
2049 | 'form_names': NameSubResource
2050 | }
2051 |
2052 | def __repr__(self):
2053 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
2054 |
2055 |
2056 | class PokemonHabitatResource(BaseResource):
2057 |
2058 | class Meta(BaseResource.Meta):
2059 | name = 'Pokemon_Habitat'
2060 | resource_name = 'pokemon-habitat'
2061 | identifier = 'id'
2062 | methods = (
2063 | 'get',
2064 | )
2065 | attributes = (
2066 | 'id',
2067 | 'name',
2068 | )
2069 | subresources = {
2070 | 'names': NameSubResource,
2071 | 'pokemon_species': NamedAPIResourceSubResource
2072 | }
2073 |
2074 | def __repr__(self):
2075 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
2076 |
2077 |
2078 | class PokemonShapeResource(BaseResource):
2079 |
2080 | class Meta(BaseResource.Meta):
2081 | name = 'Pokemon_Shape'
2082 | resource_name = 'pokemon-shape'
2083 | identifier = 'id'
2084 | methods = (
2085 | 'get',
2086 | )
2087 | attributes = (
2088 | 'id',
2089 | 'name',
2090 | )
2091 | subresources = {
2092 | 'awesome_names': AwesomeNameSubResource,
2093 | 'names': NameSubResource,
2094 | 'pokemon_species': NamedAPIResourceSubResource
2095 | }
2096 |
2097 | def __repr__(self):
2098 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
2099 |
2100 |
2101 | class PokemonSpeciesResource(BaseResource):
2102 |
2103 | class Meta(BaseResource.Meta):
2104 | name = 'Pokemon_Species'
2105 | resource_name = 'pokemon-species'
2106 | identifier = 'id'
2107 | methods = (
2108 | 'get',
2109 | )
2110 | attributes = (
2111 | 'id',
2112 | 'name',
2113 | 'order',
2114 | 'gender_rate',
2115 | 'capture_rate',
2116 | 'base_happiness',
2117 | 'is_baby',
2118 | 'is_legendary',
2119 | 'is_mythical',
2120 | 'hatch_counter',
2121 | 'has_gender_differences',
2122 | 'forms_switchable',
2123 | )
2124 | subresources = {
2125 | 'growth_rate': NamedAPIResourceSubResource,
2126 | 'pokedex_numbers': PokemonSpeciesDexEntrySubResource,
2127 | 'egg_groups': NamedAPIResourceSubResource,
2128 | 'color': NamedAPIResourceSubResource,
2129 | 'shape': NamedAPIResourceSubResource,
2130 | 'evolves_from_species': NamedAPIResourceSubResource,
2131 | 'evolution_chain': APIResourceSubResource,
2132 | 'habitat': NamedAPIResourceSubResource,
2133 | 'generation': NamedAPIResourceSubResource,
2134 | 'names': NameSubResource,
2135 | 'pal_park_encounters': PalParkEncounterAreaSubResource,
2136 | 'flavor_text_entries': FlavorTextSubResource,
2137 | 'form_descriptions': DescriptionSubResource,
2138 | 'genera': GenusSubResource,
2139 | 'varieties': PokemonSpeciesVarietySubResource
2140 | }
2141 |
2142 | def __repr__(self):
2143 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
2144 |
2145 |
2146 | class StatResource(BaseResource):
2147 |
2148 | class Meta(BaseResource.Meta):
2149 | name = 'Stat'
2150 | resource_name = 'stat'
2151 | identifier = 'id'
2152 | methods = (
2153 | 'get',
2154 | )
2155 | attributes = (
2156 | 'id',
2157 | 'name',
2158 | 'game_index',
2159 | 'is_battle_only',
2160 | )
2161 | subresources = {
2162 | 'affecting_moves': MoveStatAffectSetsSubResource,
2163 | 'affecting_natures': NatureStatAffectSetsSubResource,
2164 | 'characteristics': APIResourceSubResource,
2165 | 'move_damage_class': NamedAPIResourceSubResource,
2166 | 'names': NameSubResource
2167 | }
2168 |
2169 | def __repr__(self):
2170 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
2171 |
2172 |
2173 | class TypeResource(BaseResource):
2174 |
2175 | class Meta(BaseResource.Meta):
2176 | name = 'Type'
2177 | resource_name = 'type'
2178 | identifier = 'id'
2179 | methods = (
2180 | 'get',
2181 | )
2182 | attributes = (
2183 | 'id',
2184 | 'name',
2185 | )
2186 | subresources = {
2187 | 'damage_relations': TypeRelationsSubResource,
2188 | 'game_indices': GenerationGameIndexSubResource,
2189 | 'generation': NamedAPIResourceSubResource,
2190 | 'move_damage_class': NamedAPIResourceSubResource,
2191 | 'names': NameSubResource,
2192 | 'pokemon': TypePokemonSubResource,
2193 | 'moves': NamedAPIResourceSubResource
2194 | }
2195 |
2196 | def __repr__(self):
2197 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
2198 |
2199 |
2200 | class LanguageResource(BaseResource):
2201 |
2202 | class Meta(BaseResource.Meta):
2203 | name = 'Language'
2204 | resource_name = 'language'
2205 | identifier = 'id'
2206 | methods = (
2207 | 'get',
2208 | )
2209 | attributes = (
2210 | 'id',
2211 | 'name',
2212 | 'official',
2213 | 'iso639',
2214 | 'iso3166',
2215 | )
2216 | subresources = {
2217 | 'names': NameSubResource
2218 | }
2219 |
2220 | def __repr__(self):
2221 | return '<%s - %s>' % (self.Meta.name, self.name.capitalize())
2222 |
--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | -r requirements-dev27.txt
2 | pylint==2.1.* # style
3 | twine==1.12.* # pypi tools
4 | pyOpenSSL==19.0.* # twine dependency
5 | readme_renderer[md]==24.0.* # command 'twine check'
6 | wheel==0.32.* # command 'setup.py sdist bdist_wheel'
7 |
--------------------------------------------------------------------------------
/requirements-dev27.txt:
--------------------------------------------------------------------------------
1 | mkdocs==1.0.* # docs
2 | mkdocs-material==3.2.* # docs
3 | coverage==4.5.* # coverage
4 | requests-mock==1.5.* # tests
5 | tox==3.5.* # tests
6 | PyYAML==5.2 # mkdocs dependency (last version to support Python 3.4)
7 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | appdirs==1.4.* # dependency of FileCache
2 | beckett==0.8.* # main functionality
3 | requests==2.21.* # used by beckett (bumped to avoid CVE-2018-18074)
4 | urllib3~=1.24.3 # used by requests (bumped to avoid CVE-2019-11236)
5 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [wheel]
2 | universal = 1
3 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 | import pokepy
5 |
6 |
7 | try:
8 | from setuptools import setup
9 | except ImportError:
10 | from distutils.core import setup
11 |
12 | with open('README.md', encoding='utf-8') as readme_md,\
13 | open('docs/history.md', encoding='utf-8') as history_md,\
14 | open('requirements.txt', encoding='utf-8') as requirements_txt:
15 | readme = readme_md.read()
16 | history = history_md.read()
17 | requirements = [req[:req.find('#')].rstrip() for req in requirements_txt.readlines()]
18 |
19 | setup(
20 | name='pokepy',
21 | version=pokepy.__version__,
22 | description='A Python wrapper for PokéAPI (https://pokeapi.co)',
23 | long_description=readme + '\n\n' + history,
24 | long_description_content_type='text/markdown',
25 | license=pokepy.__license__,
26 | author=pokepy.__author__,
27 | author_email=pokepy.__email__,
28 | url='https://github.com/PokeAPI/pokepy',
29 | project_urls={'Documentation': 'https://pokeapi.github.io/pokepy/'},
30 | packages=['pokepy', 'pokepy.fcache'],
31 | package_dir={'pokepy': 'pokepy'},
32 | include_package_data=True,
33 | install_requires=requirements,
34 | zip_safe=False,
35 | keywords='pokepy PokéAPI',
36 | classifiers=[
37 | 'Development Status :: 4 - Beta',
38 | 'Intended Audience :: Developers',
39 | 'License :: OSI Approved :: BSD License',
40 | 'Natural Language :: English',
41 | 'Programming Language :: Python :: 2',
42 | 'Programming Language :: Python :: 2.7',
43 | 'Programming Language :: Python :: 3',
44 | 'Programming Language :: Python :: 3.4',
45 | 'Programming Language :: Python :: 3.5',
46 | 'Programming Language :: Python :: 3.6',
47 | 'Programming Language :: Python :: 3.7',
48 | 'Programming Language :: Python :: 3.8'
49 | ],
50 | test_suite='tests',
51 | tests_require=['requests-mock==1.5.*'],
52 | )
53 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist = py27,py34,py35,py36,py37,py38
3 |
4 | [testenv]
5 | setenv =
6 | PYTHONPATH = {toxinidir}:{toxinidir}/pokepy
7 | commands = python setup.py test
8 | deps =
9 | -r{toxinidir}/requirements.txt
10 |
--------------------------------------------------------------------------------