├── .editorconfig ├── .flake8 ├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .readthedocs.yaml ├── CONTRIBUTING.rst ├── LICENSE.txt ├── README.rst ├── docs ├── Makefile ├── api.rst ├── appendix.rst ├── conf.py ├── contributing.rst ├── index.rst └── quickstart.rst ├── pycaching ├── __init__.py ├── cache.py ├── errors.py ├── geo.py ├── geocaching.py ├── log.py ├── trackable.py └── util.py ├── pyproject.toml ├── test ├── __init__.py ├── cassettes │ ├── advanced_search.json │ ├── advanced_search_caches_owned_by_hq.json │ ├── cache_PMO.json │ ├── cache_author_deleted.json │ ├── cache_author_normal.json │ ├── cache_explicit_load.json │ ├── cache_guidload_PMO.json │ ├── cache_guidload_fallback.json │ ├── cache_guidload_normal.json │ ├── cache_hint_lazy_loading.json │ ├── cache_hint_load_by_guid.json │ ├── cache_logbook.json │ ├── cache_logpage.json │ ├── cache_non-ascii.json │ ├── cache_normal_fail.json │ ├── cache_normal_normal.json │ ├── cache_quick_normal.json │ ├── cache_quickload_fail.json │ ├── cache_setup.json │ ├── cache_status_archived.json │ ├── cache_status_disabled.json │ ├── cache_status_enabled.json │ ├── cache_status_enabled_load_quick.json │ ├── cache_status_locked.json │ ├── cache_trackables.json │ ├── cache_type_gigaevent.json │ ├── cache_type_headquarters.json │ ├── cache_type_hq_celebration.json │ ├── cache_type_locationless.json │ ├── cache_type_projectape.json │ ├── geo_location_empty.json │ ├── geo_location_existing.json │ ├── geo_location_nonexisting.json │ ├── geo_point_utfgrid.json │ ├── geocaching__try_getting_cache_from_guid.json │ ├── geocaching__try_getting_cache_from_guid_pm_only.json │ ├── geocaching_api_rate_limit.json │ ├── geocaching_api_rate_limit_with_none.json │ ├── geocaching_my_dnfs.json │ ├── geocaching_my_finds.json │ ├── geocaching_quick_search.json │ ├── geocaching_search.json │ ├── geocaching_search_pagination.json │ ├── geocaching_search_rect.json │ ├── geocaching_shortcut_geocode.json │ ├── geocaching_shortcut_getcache.json │ ├── geocaching_shortcut_getcache_by_guid.json │ ├── geocaching_shortcut_gettrackable.json │ ├── trackable_kml.json │ ├── trackable_load__existing_type.json │ ├── trackable_load__missing_type.json │ ├── trackable_load_page.json │ ├── trackable_load_tid.json │ ├── trackable_load_url.json │ ├── trackable_setup.json │ └── util_attributes.json ├── helpers.py ├── sample_caches.csv ├── sample_utfgrid.json ├── test_cache.py ├── test_geo.py ├── test_geocaching.py ├── test_log.py ├── test_trackable.py └── test_util.py └── tests_new ├── __init__.py ├── cassettes ├── tests_new.test_geocaching.TestLoadCredentials.test.json ├── tests_new.test_geocaching.TestLoadCredentials.test_file_empty.json ├── tests_new.test_geocaching.TestLoadCredentials.test_file_invalid_json.json ├── tests_new.test_geocaching.TestLoadCredentials.test_file_multiuser_empty.json ├── tests_new.test_geocaching.TestLoadCredentials.test_file_multiuser_empty_item.json ├── tests_new.test_geocaching.TestLoadCredentials.test_file_nonexisting.json ├── tests_new.test_geocaching.TestLoadCredentials.test_file_string.json ├── tests_new.test_geocaching.TestLoadCredentials.test_multiuser.json ├── tests_new.test_geocaching.TestLoadCredentials.test_multiuser_with_nonexisting_username.json ├── tests_new.test_geocaching.TestLoadCredentials.test_multiuser_with_username.json ├── tests_new.test_geocaching.TestLoadCredentials.test_password_cmd.json ├── tests_new.test_geocaching.TestLoadCredentials.test_password_cmd_ambiguous.json ├── tests_new.test_geocaching.TestLoadCredentials.test_password_cmd_invalid.json ├── tests_new.test_geocaching.TestLoadCredentials.test_with_nonexisting_username.json ├── tests_new.test_geocaching.TestLoadCredentials.test_with_username.json ├── tests_new.test_geocaching.test_get_logged_user.json ├── tests_new.test_geocaching.test_login.json ├── tests_new.test_geocaching.test_login_bad_credentials.json ├── tests_new.test_geocaching.test_login_failed_because_of_load_credentials_failed.json ├── tests_new.test_geocaching.test_login_twice_with_valid_credentials.json ├── tests_new.test_geocaching.test_logout.json ├── tests_new.test_geocaching.test_logout_when_relogin_is_attempted_with_invalid_credentials.json ├── tests_new.test_geocaching.test_unauthorized_request.json └── tests_new.test_shortcuts.test_login.json ├── conftest.py ├── test_geocaching.py └── test_shortcuts.py /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This is an ini style configuration. See http://editorconfig.org/ for more information on this file. 2 | 3 | root = true 4 | 5 | [*] 6 | end_of_line = lf 7 | charset = utf-8 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.py] 12 | indent_style = space 13 | indent_size = 4 14 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 120 3 | exclude = .venv,dist,docs,build,*.egg,.git,__pycache__,venv 4 | count = true 5 | show-source = true 6 | statistics = true 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | jobs: 4 | build: 5 | runs-on: ${{ matrix.os }} 6 | strategy: 7 | fail-fast: false 8 | matrix: 9 | os: [ ubuntu-latest, macos-latest, windows-latest ] 10 | python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] 11 | steps: 12 | - uses: actions/checkout@v3 13 | - name: Set up Python ${{ matrix.python-version }} 14 | uses: actions/setup-python@v4 15 | with: 16 | python-version: ${{ matrix.python-version }} 17 | - name: Install dependencies 18 | run: | 19 | pip install --upgrade pip setuptools flit 20 | flit install --symlink 21 | - name: isort 22 | run: isort --check --diff . 23 | - name: black 24 | run: black --check --diff . 25 | - name: flake8 26 | run: flake8 27 | - name: pytest 28 | run: pytest --cov-report=html 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Upload Python Package 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - name: Set up Python 13 | uses: actions/setup-python@v4 14 | with: 15 | python-version: '3.x' 16 | - name: Install dependencies 17 | run: | 18 | pip install --upgrade pip setuptools flit 19 | flit install --symlink 20 | - name: Build package 21 | run: flit build 22 | - name: Publish a Python distribution to PyPI 23 | uses: pypa/gh-action-pypi-publish@release/v1 24 | with: 25 | user: __token__ 26 | password: ${{ secrets.PYPI_API_TOKEN }} 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # CUSTOM =========================================================== 2 | 3 | # tmp file for testing some snippets of code 4 | test.py 5 | 6 | # testing IPython notebooks 7 | *.ipynb 8 | 9 | 10 | 11 | # DEFAULT ========================================================== 12 | 13 | # IPythonNotebook temporary data 14 | .ipynb_checkpoints/ 15 | 16 | # Byte-compiled / optimized / DLL files 17 | __pycache__/ 18 | *.py[cod] 19 | 20 | # C extensions 21 | *.so 22 | 23 | # Distribution / packaging 24 | .Python 25 | env/ 26 | build/ 27 | develop-eggs/ 28 | dist/ 29 | eggs/ 30 | lib/ 31 | lib64/ 32 | parts/ 33 | sdist/ 34 | var/ 35 | *.egg-info/ 36 | .installed.cfg 37 | *.egg 38 | .eggs/ 39 | 40 | # PyInstaller 41 | # Usually these files are written by a python script from a template 42 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 43 | *.manifest 44 | *.spec 45 | 46 | # Installer logs 47 | pip-log.txt 48 | pip-delete-this-directory.txt 49 | 50 | # Unit test / coverage reports 51 | htmlcov/ 52 | .tox/ 53 | .coverage 54 | .cache 55 | nosetests.xml 56 | coverage.xml 57 | .pytest_cache/ 58 | 59 | # Sphinx documentation 60 | docs/_build/ 61 | docs/_build_html/ 62 | 63 | # Virtualenv 64 | .Python 65 | [Bb]in 66 | [Ii]nclude 67 | [Ll]ib 68 | [Ll]ib64 69 | [Ll]ocal 70 | [Ss]cripts 71 | pyvenv.cfg 72 | .venv 73 | pip-selfcheck.json 74 | 75 | # OS X 76 | .DS_Store 77 | .AppleDouble 78 | .LSOverride 79 | Icon 80 | ._* 81 | .Spotlight-V100 82 | .Trashes 83 | .AppleDB 84 | .AppleDesktop 85 | Network Trash Folder 86 | Temporary Items 87 | .apdisk 88 | 89 | # Windows 90 | Thumbs.db 91 | Desktop.ini 92 | $RECYCLE.BIN/ 93 | 94 | # Editor 95 | *.sublime-* 96 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | version: 2 5 | 6 | # Enforce *pip*-based build to install package from *pyproject.toml* file. 7 | build: 8 | os: ubuntu-22.04 9 | tools: 10 | python: '3' 11 | 12 | python: 13 | install: 14 | - method: pip 15 | path: . 16 | extra_requirements: 17 | - docs 18 | 19 | sphinx: 20 | configuration: docs/conf.py 21 | 22 | formats: 23 | - pdf 24 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | =============================================================================== 2 | Contributing 3 | =============================================================================== 4 | 5 | 6 | First time 7 | ------------------------------------------------------------------------------- 8 | 9 | 1. Clone a repository from GitHub: 10 | 11 | .. code-block:: bash 12 | 13 | git clone https://github.com/tomasbedrich/pycaching.git 14 | cd pycaching 15 | 16 | 2. Create a virtualenv: 17 | 18 | .. code-block:: bash 19 | 20 | python3 -m venv .venv 21 | source .venv/bin/activate # Unix 22 | .venv\Scripts\activate # Windows 23 | 24 | 3. Install `Flit `_: 25 | 26 | .. code-block:: bash 27 | 28 | pip install flit 29 | 30 | 4. Install Pycaching package + dependencies in development mode: 31 | 32 | .. code-block:: bash 33 | 34 | flit install --symlink 35 | 36 | 37 | Typical workflow 38 | ------------------------------------------------------------------------------- 39 | 40 | 1. Pick an issue labeled as `"contributors friendly" 41 | `_ 42 | or create a new one. Please **notify others** that you will solve this problem (write a comment 43 | on GitHub). 44 | 45 | 2. Activate the virtualenv: 46 | 47 | .. code-block:: bash 48 | 49 | source .venv/bin/activate # Unix 50 | .venv\Scripts\activate # Windows 51 | 52 | 3. Write some **code and tests**. After that, don't forget to update the **docs**. See coding style below. 53 | 54 | 4. Sort imports using `isort `_, 55 | format the code using `Black `_, 56 | lint it using `Flake `_ and 57 | run the tests using `pytest `_: 58 | 59 | .. code-block:: bash 60 | 61 | isort . 62 | black . 63 | flake8 64 | pytest 65 | 66 | Make sure that: 67 | 68 | - there are no lint errors, 69 | - all tests are passing, 70 | - the coverage is above 90%. 71 | 72 | 6. Push your work and create a **pull request**. Yay! 73 | 74 | 75 | Testing 76 | ------------------------------------------------------------------------------- 77 | 78 | Pycaching uses `Betamax `__ for testing, which speeds 79 | it up by recording network requests so that they can be mocked. 80 | 81 | If you haven't written or modified any tests, tests can be run just like: 82 | 83 | .. code-block:: bash 84 | 85 | pytest 86 | 87 | If you have written or modified tests, you must provide a username and password for testing. Don't 88 | worry, these will not leave your computer. Betamax will insert a placeholder when it records any 89 | new cassettes. To run new tests, first set up the following environment variables: 90 | 91 | .. code-block:: bash 92 | 93 | PYCACHING_TEST_USERNAME="yourusername" PYCACHING_TEST_PASSWORD="yourpassword" pytest 94 | 95 | Substitute your username for ``yourusername`` and your password for ``yourpassword``. 96 | This requires you to use a basic member account, otherwise you might see unexpected test failures. 97 | 98 | To re-record a specific cassette in case of site changes, delete the corresponding JSON file and 99 | provide username and password as explained above. The missing cassette will be recorded for future 100 | usages. 101 | 102 | 103 | Coding style 104 | ------------------------------------------------------------------------------- 105 | 106 | - Use `.format()` for string formatting. Black will guide you with the rest. :) 107 | - For docs, please follow `PEP257 `_. 108 | - **Importing modules** is okay for modules from standard library. If you want to include a 109 | third-party module, please consult it on GitHub before. 110 | - `Please use regular expressions only as a last resort. `_ When possible, use string manipulations, 111 | such as :code:`split()` and then list operations. It is more readable. 112 | 113 | 114 | Release process 115 | ------------------------------------------------------------------------------- 116 | 117 | 1. Pick a suitable semantic version number. We adhere to `generic rules `_ with an exception of our `specific deprecation policy `_. 118 | 2. If the deprecation policy triggers, remove the deprecated methods. Create a separate PR in that case. 119 | 3. Bump the version number in ``pycaching/__init__.py`` (`example `_). Feel free to push this bump directly to ``master``, or create a regular PR. 120 | 4. Once the version bump commit equals HEAD of ``master``, `draft a new release `_ using Github. Using that form, create a new tag corresponding to the version number (no prefixes). Leave release title empty, let Github generate the release notes. Update release notes manually if needed. 121 | 5. Publish the Github release. There is a Github action which publishes the release to Pypi. There are Webhooks which update Readthedocs and Coveralls. 122 | 123 | Should there be any issue with the above (most likely stuck release pipeline), please create a Github issue. 124 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | =================================================================================================== 2 | pycaching - Geocaching for Python 3 | =================================================================================================== 4 | 5 | Complete documentation can be found at `Read the Docs `_. 6 | 7 | .. _features: 8 | 9 | Features 10 | =================================================================================================== 11 | 12 | - **login** to Geocaching.com 13 | - **search** caches 14 | 15 | - normal search (unlimited number of caches from any point) 16 | - quick search (all caches inside some area) - currently not working, see below 17 | 18 | - **get cache** and its details 19 | 20 | - normal loading (can load all details) 21 | - quick loading (can load just basic info but very quickly) 22 | - load logbook for given cache 23 | 24 | - **get trackable** details by tracking code 25 | - **post log** for a cache or a trackable 26 | - **geocode** given location 27 | 28 | .. _installation: 29 | 30 | Installation 31 | =================================================================================================== 32 | 33 | Stable version - using pip: 34 | 35 | .. code-block:: bash 36 | 37 | pip install pycaching 38 | 39 | Dev version - manually from GIT: 40 | 41 | .. code-block:: bash 42 | 43 | git clone https://github.com/tomasbedrich/pycaching.git 44 | cd pycaching 45 | pip install . 46 | 47 | Pycaching has following requirements: 48 | 49 | .. code:: 50 | 51 | Python>=3.5 52 | requests>=2.8 53 | beautifulsoup4>=4.9 54 | geopy>=1.11 55 | 56 | Pycaching tests have the following additional requirements: 57 | 58 | .. code:: 59 | 60 | betamax >=0.8, <0.9 61 | betamax-serializers >=0.2, <0.3 62 | 63 | Examples 64 | =================================================================================================== 65 | 66 | Login 67 | --------------------------------------------------------------------------------------------------- 68 | 69 | Simply call `pycaching.login() 70 | `__ 71 | method and it will do everything for you. 72 | 73 | .. code-block:: python 74 | 75 | import pycaching 76 | geocaching = pycaching.login("user", "pass") 77 | 78 | If you won't provide an username or password, pycaching will try to load ``.gc_credentials`` file 79 | from current directory or home folder. It will try to parse it as JSON and use the keys ``username`` 80 | and ``password`` from that file as login credentials. 81 | 82 | .. code-block:: json 83 | 84 | { "username": "myusername", "password": "mypassword" } 85 | 86 | 87 | You can also provide multiple username and password tuples in a file as login credentials. 88 | The tuple to be used can be chosen by providing its username when calling ``pycaching.login()``, 89 | e.g. ``pycaching.login("myusername2")``. The first username and password tuple specified will be 90 | used as default if ``pycaching.login()`` is called without providing a username. 91 | 92 | .. code-block:: json 93 | 94 | [ { "username": "myusername1", "password": "mypassword1" }, 95 | { "username": "myusername2", "password": "mypassword2" } ] 96 | 97 | 98 | .. code-block:: python 99 | 100 | import pycaching 101 | geocaching = pycaching.login() # assume the .gc_credentials file is presented 102 | 103 | In case you have a password manager in place featuring a command line interface 104 | (e.g. `GNU pass `__) you may specify a password retrieval command 105 | using the ``password_cmd`` key instead of ``password``. 106 | 107 | .. code-block:: json 108 | 109 | { "username": "myusername", "password_cmd": "pass geocaching.com/myUsername" } 110 | 111 | Note that the ``password`` and ``password_cmd`` keys are mutually exclusive. 112 | 113 | 114 | 115 | Load a cache details 116 | --------------------------------------------------------------------------------------------------- 117 | 118 | .. code-block:: python 119 | 120 | cache = geocaching.get_cache("GC1PAR2") 121 | print(cache.name) # cache.load() is automatically called 122 | print(cache.location) # stored in cache, printed immediately 123 | 124 | This uses lazy loading, so the `Cache `__ 125 | object is created immediately and the page is loaded when needed (accessing the name). 126 | 127 | You can use a different method of loading cache details. It will be much faster, but it will load less 128 | details: 129 | 130 | .. code-block:: python 131 | 132 | cache = geocaching.get_cache("GC1PAR2") 133 | cache.load_quick() # takes a small while 134 | print(cache.name) # stored in cache, printed immediately 135 | print(cache.location) # NOT stored in cache, will trigger full loading 136 | 137 | You can also load a logbook for cache: 138 | 139 | .. code-block:: python 140 | 141 | for log in cache.load_logbook(limit=200): 142 | print(log.visited, log.type, log.author, log.text) 143 | 144 | Or its trackables: 145 | 146 | .. code-block:: python 147 | 148 | for trackable in cache.load_trackables(limit=5): 149 | print(trackable.name) 150 | 151 | Post a log to cache 152 | --------------------------------------------------------------------------------------------------- 153 | 154 | .. code-block:: python 155 | 156 | geocaching.post_log("GC1PAR2", "Found cache in the rain. Nice place, TFTC!") 157 | 158 | It is also possible to call ``post_log`` on `Cache 159 | `__ object, but you would have to create 160 | `Log `__ object manually and pass it to 161 | this method. 162 | 163 | Search for all traditional caches around 164 | --------------------------------------------------------------------------------------------------- 165 | 166 | .. code-block:: python 167 | 168 | from pycaching import Point 169 | from pycaching.cache import Type 170 | 171 | point = Point(56.25263, 15.26738) 172 | 173 | for cache in geocaching.search(point, limit=50): 174 | if cache.type == Type.traditional: 175 | print(cache.name) 176 | 177 | Notice the ``limit`` in the search function. It is because `geocaching.search() 178 | `__ 179 | returns a generator object, which would fetch the caches forever in case of a simple loop. 180 | 181 | Geocode address and search around 182 | --------------------------------------------------------------------------------------------------- 183 | 184 | .. code-block:: python 185 | 186 | point = geocaching.geocode("Prague") 187 | 188 | for cache in geocaching.search(point, limit=10): 189 | print(cache.name) 190 | 191 | Find caches in some area 192 | --------------------------------------------------------------------------------------------------- 193 | 194 | .. code-block:: python 195 | 196 | from pycaching import Point, Rectangle 197 | 198 | rect = Rectangle(Point(60.15, 24.95), Point(60.17, 25.00)) 199 | 200 | for cache in geocaching.search_rect(rect): 201 | print(cache.name) 202 | 203 | If you want to search in a larger area, you could use the ``limit`` parameter as described above. 204 | 205 | Load trackable details 206 | --------------------------------------------------------------------------------------------------- 207 | 208 | .. code-block:: python 209 | 210 | trackable = geocaching.get_trackable("TB3ZGT2") 211 | print(trackable.name, trackable.goal, trackable.description, trackable.location) 212 | 213 | 214 | Post a log for trackable 215 | --------------------------------------------------------------------------------------------------- 216 | 217 | .. code-block:: python 218 | 219 | from pycaching.log import Log, Type as LogType 220 | import datetime 221 | 222 | log = Log(type=LogType.discovered_it, text="Nice TB!", visited=datetime.date.today()) 223 | tracking_code = "ABCDEF" 224 | trackable.post_log(log, tracking_code) 225 | 226 | Get geocaches by log type 227 | --------------------------------------------------------------------------------------------------- 228 | 229 | .. code-block:: python 230 | 231 | from pycaching.log import Type as LogType 232 | 233 | for find in geocaching.my_finds(limit=5): 234 | print(find.name) 235 | 236 | for dnf in geocaching.my_dnfs(limit=2): 237 | print(dnf.name) 238 | 239 | for note in geocaching.my_logs(LogType.note, limit=6): 240 | print(note.name) 241 | 242 | 243 | .. _appendix: 244 | 245 | Appendix 246 | =================================================================================================== 247 | 248 | Legal notice 249 | --------------------------------------------------------------------------------------------------- 250 | 251 | Be sure to read `Geocaching.com's terms of use `__. 252 | By using this piece of software you break them and your Geocaching account may be suspended or *even 253 | deleted*. To prevent this, I recommend you to load the data you really need, nothing more. This 254 | software is provided "as is" and I am not responsible for any damage possibly caused by it. 255 | 256 | Inspiration 257 | --------------------------------------------------------------------------------------------------- 258 | 259 | Original version was inspired by these packages: 260 | 261 | - `Geocache Grabber `__ (by Fuad Tabba) 262 | - `geocaching-py `__ (by Lev Shamardin) 263 | 264 | Although the new version was massively rewritten, I'd like to thank to their authors. 265 | 266 | Authors 267 | --------------------------------------------------------------------------------------------------- 268 | 269 | Authors of this project are `all contributors 270 | `__. Maintainer is `Tomáš Bedřich 271 | `__. 272 | 273 | .. _build_status: 274 | 275 | |PyPI monthly downloads| 276 | 277 | .. |PyPI monthly downloads| image:: http://img.shields.io/pypi/dm/pycaching.svg 278 | :target: https://pypi.python.org/pypi/pycaching 279 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " applehelp to make an Apple Help Book" 34 | @echo " devhelp to make HTML files and a Devhelp project" 35 | @echo " epub to make an epub" 36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 37 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 39 | @echo " text to make text files" 40 | @echo " man to make manual pages" 41 | @echo " texinfo to make Texinfo files" 42 | @echo " info to make Texinfo files and run them through makeinfo" 43 | @echo " gettext to make PO message catalogs" 44 | @echo " changes to make an overview of all changed/added/deprecated items" 45 | @echo " xml to make Docutils-native XML files" 46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 47 | @echo " linkcheck to check all external links for integrity" 48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 49 | @echo " coverage to run coverage check of the documentation (if enabled)" 50 | 51 | clean: 52 | rm -rf $(BUILDDIR)/* 53 | 54 | html: 55 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 56 | @echo 57 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 58 | 59 | dirhtml: 60 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 61 | @echo 62 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 63 | 64 | singlehtml: 65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 66 | @echo 67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 68 | 69 | pickle: 70 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 71 | @echo 72 | @echo "Build finished; now you can process the pickle files." 73 | 74 | json: 75 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 76 | @echo 77 | @echo "Build finished; now you can process the JSON files." 78 | 79 | htmlhelp: 80 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 81 | @echo 82 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 83 | ".hhp project file in $(BUILDDIR)/htmlhelp." 84 | 85 | qthelp: 86 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 87 | @echo 88 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 89 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 90 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pycaching.qhcp" 91 | @echo "To view the help file:" 92 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pycaching.qhc" 93 | 94 | applehelp: 95 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 96 | @echo 97 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 98 | @echo "N.B. You won't be able to view it unless you put it in" \ 99 | "~/Library/Documentation/Help or install it in your application" \ 100 | "bundle." 101 | 102 | devhelp: 103 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 104 | @echo 105 | @echo "Build finished." 106 | @echo "To view the help file:" 107 | @echo "# mkdir -p $$HOME/.local/share/devhelp/pycaching" 108 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pycaching" 109 | @echo "# devhelp" 110 | 111 | epub: 112 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 113 | @echo 114 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 115 | 116 | latex: 117 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 118 | @echo 119 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 120 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 121 | "(use \`make latexpdf' here to do that automatically)." 122 | 123 | latexpdf: 124 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 125 | @echo "Running LaTeX files through pdflatex..." 126 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 127 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 128 | 129 | latexpdfja: 130 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 131 | @echo "Running LaTeX files through platex and dvipdfmx..." 132 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 133 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 134 | 135 | text: 136 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 137 | @echo 138 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 139 | 140 | man: 141 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 142 | @echo 143 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 144 | 145 | texinfo: 146 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 147 | @echo 148 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 149 | @echo "Run \`make' in that directory to run these through makeinfo" \ 150 | "(use \`make info' here to do that automatically)." 151 | 152 | info: 153 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 154 | @echo "Running Texinfo files through makeinfo..." 155 | make -C $(BUILDDIR)/texinfo info 156 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 157 | 158 | gettext: 159 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 160 | @echo 161 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 162 | 163 | changes: 164 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 165 | @echo 166 | @echo "The overview file is in $(BUILDDIR)/changes." 167 | 168 | linkcheck: 169 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 170 | @echo 171 | @echo "Link check complete; look for any errors in the above output " \ 172 | "or in $(BUILDDIR)/linkcheck/output.txt." 173 | 174 | doctest: 175 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 176 | @echo "Testing of doctests in the sources finished, look at the " \ 177 | "results in $(BUILDDIR)/doctest/output.txt." 178 | 179 | coverage: 180 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 181 | @echo "Testing of coverage in the sources finished, look at the " \ 182 | "results in $(BUILDDIR)/coverage/python.txt." 183 | 184 | xml: 185 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 186 | @echo 187 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 188 | 189 | pseudoxml: 190 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 191 | @echo 192 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 193 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | =============================================================================== 2 | API reference 3 | =============================================================================== 4 | 5 | Here you can find an overview of all available classes and methods. 6 | 7 | .. warning:: 8 | Deprecated methods will be removed in next minor version. 9 | 10 | For example: if you rely on some non-deprecated method in version 3.3, then it's fine to update 11 | once to 3.4. If the method gets deprecated in 3.4, then it will be removed in 3.5! 12 | 13 | .. automodule:: pycaching 14 | :members: login 15 | 16 | 17 | Geocaching 18 | ------------------------------------------------------------------------------- 19 | 20 | .. automodule:: pycaching.geocaching 21 | :members: 22 | 23 | 24 | Cache 25 | ------------------------------------------------------------------------------- 26 | 27 | .. autoclass:: pycaching.cache.Cache 28 | :members: 29 | 30 | .. autoclass:: pycaching.cache.Waypoint 31 | :members: 32 | :undoc-members: 33 | :inherited-members: 34 | 35 | .. autoclass:: pycaching.cache.Type 36 | :members: 37 | :undoc-members: 38 | :inherited-members: 39 | 40 | .. autoclass:: pycaching.cache.Size 41 | :members: 42 | :undoc-members: 43 | :inherited-members: 44 | 45 | 46 | Logs 47 | ------------------------------------------------------------------------------- 48 | 49 | .. autoclass:: pycaching.log.Log 50 | :members: 51 | 52 | .. autoclass:: pycaching.log.Type 53 | :members: 54 | :undoc-members: 55 | :inherited-members: 56 | 57 | 58 | Trackables 59 | ------------------------------------------------------------------------------- 60 | 61 | .. automodule:: pycaching.trackable 62 | :members: 63 | 64 | 65 | Geo utilities 66 | ------------------------------------------------------------------------------- 67 | 68 | .. automodule:: pycaching.geo 69 | :members: to_decimal 70 | 71 | .. autoclass:: pycaching.geo.Point 72 | :members: from_location, from_string 73 | 74 | .. autoclass:: pycaching.geo.Polygon 75 | :members: bounding_box, mean_point 76 | 77 | .. autoclass:: pycaching.geo.Rectangle 78 | :members: __contains__, diagonal 79 | 80 | 81 | Errors 82 | ------------------------------------------------------------------------------- 83 | 84 | .. automodule:: pycaching.errors 85 | :members: 86 | -------------------------------------------------------------------------------- /docs/appendix.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | :start-after: _appendix: 3 | :end-before: _build_status: 4 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # pycaching documentation build configuration file, created by 5 | # sphinx-quickstart on Sun Nov 15 15:53:50 2015. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | import sys 17 | from datetime import date 18 | from pathlib import Path 19 | 20 | import sphinx_rtd_theme 21 | 22 | # If extensions (or modules to document with autodoc) are in another directory, 23 | # add these directories to sys.path here. If the directory is relative to the 24 | # documentation root, use os.path.abspath to make it absolute, like shown here. 25 | 26 | sys.path.append(str(Path("..").resolve())) 27 | 28 | import pycaching 29 | 30 | # -- General configuration ------------------------------------------------ 31 | 32 | # If your documentation needs a minimal Sphinx version, state it here. 33 | # needs_sphinx = '1.0' 34 | 35 | # Add any Sphinx extension module names here, as strings. They can be 36 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 37 | # ones. 38 | extensions = [ 39 | "sphinx.ext.autodoc", 40 | # 'sphinx.ext.doctest', 41 | "sphinx.ext.intersphinx", 42 | # 'sphinx.ext.coverage', 43 | ] 44 | 45 | # Add any paths that contain templates here, relative to this directory. 46 | templates_path = ["_templates"] 47 | 48 | # The suffix(es) of source filenames. 49 | # You can specify multiple suffix as a list of string: 50 | # source_suffix = ['.rst', '.md'] 51 | source_suffix = ".rst" 52 | 53 | # The encoding of source files. 54 | # source_encoding = 'utf-8-sig' 55 | 56 | # The master toctree document. 57 | master_doc = "index" 58 | 59 | # General information about the project. 60 | project = "pycaching" 61 | copyright = "2015-{}, pycaching contributors".format(date.today().year) 62 | author = "pycaching contributors" 63 | 64 | # The version info for the project you're documenting, acts as replacement for 65 | # |version| and |release|, also used in various other places throughout the 66 | # built documents. 67 | # 68 | configured_version = pycaching.__version__ 69 | # The short X.Y version. 70 | version = ".".join(configured_version.split(".")[:2]) 71 | # The full version, including alpha/beta/rc tags. 72 | release = configured_version 73 | 74 | # The language for content autogenerated by Sphinx. Refer to documentation 75 | # for a list of supported languages. 76 | # 77 | # This is also used if you do content translation via gettext catalogs. 78 | # Usually you set "language" from the command line for these cases. 79 | language = "en" 80 | 81 | # There are two options for replacing |today|: either, you set today to some 82 | # non-false value, then it is used: 83 | # today = '' 84 | # Else, today_fmt is used as the format for a strftime call. 85 | # today_fmt = '%B %d, %Y' 86 | 87 | # List of patterns, relative to source directory, that match files and 88 | # directories to ignore when looking for source files. 89 | exclude_patterns = ["_build"] 90 | 91 | # The reST default role (used for this markup: `text`) to use for all 92 | # documents. 93 | # default_role = None 94 | 95 | # If true, '()' will be appended to :func: etc. cross-reference text. 96 | # add_function_parentheses = True 97 | 98 | # If true, the current module name will be prepended to all description 99 | # unit titles (such as .. function::). 100 | # add_module_names = True 101 | 102 | # If true, sectionauthor and moduleauthor directives will be shown in the 103 | # output. They are ignored by default. 104 | # show_authors = False 105 | 106 | # The name of the Pygments (syntax highlighting) style to use. 107 | pygments_style = "sphinx" 108 | 109 | # A list of ignored prefixes for module index sorting. 110 | # modindex_common_prefix = [] 111 | 112 | # If true, keep warnings as "system message" paragraphs in the built documents. 113 | # keep_warnings = False 114 | 115 | # If true, `todo` and `todoList` produce output, else they produce nothing. 116 | todo_include_todos = False 117 | 118 | 119 | # -- Options for HTML output ---------------------------------------------- 120 | 121 | # The theme to use for HTML and HTML Help pages. See the documentation for 122 | # a list of builtin themes. 123 | html_theme = "sphinx_rtd_theme" 124 | 125 | # Theme options are theme-specific and customize the look and feel of a theme 126 | # further. For a list of options available for each theme, see the 127 | # documentation. 128 | # html_theme_options = {} 129 | 130 | # Add any paths that contain custom themes here, relative to this directory. 131 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 132 | 133 | # The name for this set of Sphinx documents. If None, it defaults to 134 | # " v documentation". 135 | # html_title = None 136 | 137 | # A shorter title for the navigation bar. Default is the same as html_title. 138 | # html_short_title = None 139 | 140 | # The name of an image file (relative to this directory) to place at the top 141 | # of the sidebar. 142 | # html_logo = None 143 | 144 | # The name of an image file (within the static path) to use as favicon of the 145 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 146 | # pixels large. 147 | # html_favicon = None 148 | 149 | # Add any paths that contain custom static files (such as style sheets) here, 150 | # relative to this directory. They are copied after the builtin static files, 151 | # so a file named "default.css" will overwrite the builtin "default.css". 152 | html_static_path = ["_static"] 153 | 154 | # Add any extra paths that contain custom files (such as robots.txt or 155 | # .htaccess) here, relative to this directory. These files are copied 156 | # directly to the root of the documentation. 157 | # html_extra_path = [] 158 | 159 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 160 | # using the given strftime format. 161 | # html_last_updated_fmt = '%b %d, %Y' 162 | 163 | # If true, SmartyPants will be used to convert quotes and dashes to 164 | # typographically correct entities. 165 | # html_use_smartypants = True 166 | 167 | # Custom sidebar templates, maps document names to template names. 168 | # html_sidebars = {} 169 | 170 | # Additional templates that should be rendered to pages, maps page names to 171 | # template names. 172 | # html_additional_pages = {} 173 | 174 | # If false, no module index is generated. 175 | # html_domain_indices = True 176 | 177 | # If false, no index is generated. 178 | # html_use_index = True 179 | 180 | # If true, the index is split into individual pages for each letter. 181 | # html_split_index = False 182 | 183 | # If true, links to the reST sources are added to the pages. 184 | # html_show_sourcelink = True 185 | 186 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 187 | # html_show_sphinx = True 188 | 189 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 190 | # html_show_copyright = True 191 | 192 | # If true, an OpenSearch description file will be output, and all pages will 193 | # contain a tag referring to it. The value of this option must be the 194 | # base URL from which the finished HTML is served. 195 | # html_use_opensearch = '' 196 | 197 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 198 | # html_file_suffix = None 199 | 200 | # Language to be used for generating the HTML full-text search index. 201 | # Sphinx supports the following languages: 202 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' 203 | # 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' 204 | # html_search_language = 'en' 205 | 206 | # A dictionary with options for the search language support, empty by default. 207 | # Now only 'ja' uses this config value 208 | # html_search_options = {'type': 'default'} 209 | 210 | # The name of a javascript file (relative to the configuration directory) that 211 | # implements a search results scorer. If empty, the default will be used. 212 | # html_search_scorer = 'scorer.js' 213 | 214 | # Output file base name for HTML help builder. 215 | htmlhelp_basename = "pycachingdoc" 216 | 217 | # -- Options for LaTeX output --------------------------------------------- 218 | 219 | latex_elements = { 220 | # The paper size ('letterpaper' or 'a4paper'). 221 | #'papersize': 'letterpaper', 222 | # The font size ('10pt', '11pt' or '12pt'). 223 | #'pointsize': '10pt', 224 | # Additional stuff for the LaTeX preamble. 225 | #'preamble': '', 226 | # Latex figure (float) alignment 227 | #'figure_align': 'htbp', 228 | } 229 | 230 | # Grouping the document tree into LaTeX files. List of tuples 231 | # (source start file, target name, title, 232 | # author, documentclass [howto, manual, or own class]). 233 | latex_documents = [ 234 | (master_doc, "pycaching.tex", "pycaching Documentation", "Tomáš Bedřich", "manual"), 235 | ] 236 | 237 | # The name of an image file (relative to this directory) to place at the top of 238 | # the title page. 239 | # latex_logo = None 240 | 241 | # For "manual" documents, if this is true, then toplevel headings are parts, 242 | # not chapters. 243 | # latex_use_parts = False 244 | 245 | # If true, show page references after internal links. 246 | # latex_show_pagerefs = False 247 | 248 | # If true, show URL addresses after external links. 249 | # latex_show_urls = False 250 | 251 | # Documents to append as an appendix to all manuals. 252 | # latex_appendices = [] 253 | 254 | # If false, no module index is generated. 255 | # latex_domain_indices = True 256 | 257 | 258 | # -- Options for manual page output --------------------------------------- 259 | 260 | # One entry per manual page. List of tuples 261 | # (source start file, name, description, authors, manual section). 262 | man_pages = [(master_doc, "pycaching", "pycaching Documentation", [author], 1)] 263 | 264 | # If true, show URL addresses after external links. 265 | # man_show_urls = False 266 | 267 | 268 | # -- Options for Texinfo output ------------------------------------------- 269 | 270 | # Grouping the document tree into Texinfo files. List of tuples 271 | # (source start file, target name, title, author, 272 | # dir menu entry, description, category) 273 | texinfo_documents = [ 274 | ( 275 | master_doc, 276 | "pycaching", 277 | "pycaching Documentation", 278 | author, 279 | "pycaching", 280 | "One line description of project.", 281 | "Miscellaneous", 282 | ), 283 | ] 284 | 285 | # Documents to append as an appendix to all manuals. 286 | # texinfo_appendices = [] 287 | 288 | # If false, no module index is generated. 289 | # texinfo_domain_indices = True 290 | 291 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 292 | # texinfo_show_urls = 'footnote' 293 | 294 | # If true, do not generate a @detailmenu in the "Top" node's menu. 295 | # texinfo_no_detailmenu = False 296 | 297 | 298 | # Example configuration for intersphinx: refer to the Python standard library. 299 | intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} 300 | 301 | 302 | # -- Options for autodoc ----------------------------------------------- 303 | 304 | autodoc_member_order = "groupwise" 305 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | =================================================================================================== 2 | pycaching - Geocaching for Python 3 | =================================================================================================== 4 | 5 | Source codes can be found at `GitHub repository `_. 6 | 7 | .. include:: ../README.rst 8 | :start-after: _features: 9 | :end-before: _installation: 10 | 11 | 12 | Documentation contents 13 | =============================================================================== 14 | 15 | 16 | .. toctree:: 17 | :maxdepth: 2 18 | 19 | quickstart 20 | api 21 | contributing 22 | appendix 23 | -------------------------------------------------------------------------------- /docs/quickstart.rst: -------------------------------------------------------------------------------- 1 | =============================================================================== 2 | Quickstart 3 | =============================================================================== 4 | 5 | 6 | .. include:: ../README.rst 7 | :start-after: _installation: 8 | :end-before: _appendix: 9 | -------------------------------------------------------------------------------- /pycaching/__init__.py: -------------------------------------------------------------------------------- 1 | from pycaching.cache import Cache # NOQA 2 | from pycaching.geo import Point, Rectangle # NOQA 3 | from pycaching.geocaching import Geocaching # NOQA 4 | from pycaching.log import Log # NOQA 5 | from pycaching.trackable import Trackable # NOQA 6 | 7 | __version__ = "4.4.3" # PEP 440 8 | 9 | 10 | def login(username=None, password=None): 11 | """A shortcut for user login. 12 | 13 | Create a :class:`.Geocaching` instance and try to login a user. See :meth:`.Geocaching.login`. 14 | 15 | :return: Created :class:`.Geocaching` instance. 16 | """ 17 | g = Geocaching() 18 | g.login(username, password) 19 | return g 20 | -------------------------------------------------------------------------------- /pycaching/errors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | class Error(Exception): 5 | """General pycaching error. 6 | 7 | .. note: 8 | This class is a superclass of all errors produced by pycaching module, so you can use it to 9 | catch all pycaching related errors. 10 | """ 11 | 12 | 13 | class NotLoggedInException(Error): 14 | """Tried to perform an operation which requires logging in first.""" 15 | 16 | 17 | class LoginFailedException(Error, ValueError): 18 | """Login failed. 19 | 20 | The provided credentials probably doesn't work to log in. 21 | """ 22 | 23 | 24 | class GeocodeError(Error, ValueError): 25 | """Geocoding failed. 26 | 27 | Probably because of non-existing location. 28 | """ 29 | 30 | 31 | class LoadError(Error, OSError): 32 | """Object loading failed. 33 | 34 | Probably because of non-existing object or missing informations required to load it. 35 | """ 36 | 37 | 38 | class PMOnlyException(Error): 39 | """Requested cache is PM only.""" 40 | 41 | 42 | class BadBlockError(Error): 43 | pass 44 | 45 | 46 | class ValueError(Error, ValueError): 47 | """Wrapper for Pythons native ValueError. 48 | 49 | Can be raised in various situations, but most commonly when unexpected property value is set. 50 | """ 51 | 52 | 53 | class TooManyRequestsError(Error): 54 | """Geocaching API rate limit has been reached.""" 55 | 56 | def __init__(self, url: str, rate_limit_reset: int = 0): 57 | """ 58 | Initialize TooManyRequestsError. 59 | 60 | :param url: Requested url. 61 | :param rate_limit_reset: Number of seconds to wait before rate limit reset. 62 | """ 63 | self.url = url 64 | self.rate_limit_reset = rate_limit_reset 65 | 66 | def wait_for(self): 67 | """Wait enough time to release Rate Limits.""" 68 | import time 69 | 70 | time.sleep(self.rate_limit_reset + 5) 71 | -------------------------------------------------------------------------------- /pycaching/log.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import datetime 4 | import enum 5 | 6 | from pycaching import errors 7 | from pycaching.util import parse_date 8 | 9 | # prefix _type() function to avoid colisions with log type 10 | _type = type 11 | 12 | 13 | class Log(object): 14 | """Represents a log record with its properties.""" 15 | 16 | def __init__(self, *, uuid=None, type=None, text=None, visited=None, author=None): 17 | if uuid is not None: 18 | self.uuid = uuid 19 | if type is not None: 20 | self.type = type 21 | if text is not None: 22 | self.text = text 23 | if visited is not None: 24 | self.visited = visited 25 | if author is not None: 26 | self.author = author 27 | 28 | def __str__(self): 29 | """Return log text.""" 30 | return self.text 31 | 32 | @property 33 | def uuid(self): 34 | """The log unique identifier. 35 | 36 | :type: :class:`str` 37 | """ 38 | return self._uuid 39 | 40 | @uuid.setter 41 | def uuid(self, uuid): 42 | self._uuid = uuid 43 | 44 | @property 45 | def type(self): 46 | """The log type. 47 | 48 | :type: :class:`.log.Type` 49 | """ 50 | return self._type 51 | 52 | @type.setter 53 | def type(self, type): 54 | self._type = type 55 | 56 | @property 57 | def text(self): 58 | """The log text. 59 | 60 | :type: :class:`str` 61 | """ 62 | return self._text 63 | 64 | @text.setter 65 | def text(self, text): 66 | text = str(text).strip() 67 | self._text = text 68 | 69 | @property 70 | def visited(self): 71 | """The log date. 72 | 73 | :setter: Set a log date. If :class:`str` is passed, then :meth:`.util.parse_date` 74 | is used and its return value is stored as a date. 75 | :type: :class:`datetime.date` 76 | """ 77 | return self._visited 78 | 79 | @visited.setter 80 | def visited(self, visited): 81 | if _type(visited) is str: 82 | visited = parse_date(visited) 83 | elif _type(visited) is not datetime.date: 84 | raise errors.ValueError("Passed object is not datetime.date instance nor string containing a date.") 85 | self._visited = visited 86 | 87 | @property 88 | def author(self): 89 | """The log author. 90 | 91 | :type: :class:`str` 92 | """ 93 | return self._author 94 | 95 | @author.setter 96 | def author(self, author): 97 | self._author = author.strip() 98 | 99 | 100 | class Type(enum.Enum): 101 | """Enum of possible log types. 102 | 103 | Values are log type IDs (as used in HTML