diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 91d02722..cebbd76d 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -3,6 +3,7 @@ Thanks to the following individuals for providing pull requests, feedback, bug r questions, and other contributions that have helped to improve pyinaturalist: * [AE Hamrick](https://github.com/AEHamrick) +* [Ben Armstrong](https://github.com/synrg) * [Felipe S Barros](https://github.com/FelipeSBarros) * [Ken-ichi Ueda](https://github.com/kueda/) * [Matt Muir](https://forum.inaturalist.org/u/muir) diff --git a/HISTORY.md b/HISTORY.md index 46ed6075..212aaec8 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,6 @@ # History -## 0.14 (2021-TBD) +## 0.14 (2021-07-TBD) [See all Issues & PRs for 0.14](https://github.com/niconoe/pyinaturalist/milestone/5?closed=1) ### New Endpoints @@ -61,8 +61,8 @@ Model features: ### Other Changes * Consolidated response formatting into a single `pprint()` function (instead of one per resource type) * Refactored and reorganized the following internal utility modules (see API docs for details): - * `api_docs` * `converters` + * `docs` * `formatters` * `request_params` * Added a default response timeout of 5 seconds diff --git a/README.md b/README.md index eb6105d4..f951eda4 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,10 @@ about iNaturalist, the [iNaturalist Community Forum](https://forum.inaturalist.o place to start. ## Related Projects +Other python projects related to iNaturalist: + +* [Dronefly](https://github.com/synrg/dronefly): A Discord bot with iNaturalist data access features, +* [pyinaturalist-convert](https://github.com/JWCook/pyinaturalist-convert): Tools to convert observation data to and from multiple formats * [pyinaturalist-open-data](https://github.com/JWCook/pyinaturalist-open-data): Tools for working with [iNaturalist open data](https://registry.opendata.aws/inaturalist-open-data/) * [pyinaturalist-notebook](https://github.com/JWCook/pyinaturalist-notebook): Jupyter notebook Docker image for pyinaturalist -* [pyinaturalist-convert](https://github.com/JWCook/pyinaturalist-convert): (WIP) Tools to convert observation data to and from multiple formats + used by the iNaturalist Discord server. diff --git a/docs/conf.py b/docs/conf.py index f18f7a8a..33587ed9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -3,7 +3,7 @@ * ``forge`` is used to define and reuse documentation for API request parameters * ``apidoc`` is used to generate rst sources for **modules** * ``autosummary`` is used to generate rst sources for **packages and summaries** -* ``automodapi`` + ``pyinaturalist.api_docs.model_docs`` are used to generate model +* ``automodapi`` + ``pyinaturalist.docs.model_docs`` are used to generate model documentation based on ``attrs`` fields + metadata * ``intersphinx`` is used to insert links to other projects' docs * Jinja templates provide some additional customization: @@ -34,7 +34,7 @@ sys.path.insert(0, '..') from pyinaturalist import __version__ from pyinaturalist.constants import DOCS_DIR, PROJECT_DIR, EXAMPLES_DIR, SAMPLE_DATA_DIR -from pyinaturalist.api_docs.model_docs import document_models +from pyinaturalist.docs.model_docs import document_models # Relevant doc directories used in extension settings CSS_DIR = join(DOCS_DIR, '_static') @@ -118,7 +118,7 @@ # apidoc settings apidoc_module_dir = PACKAGE_DIR apidoc_output_dir = MODULE_DOCS_DIR -apidoc_excluded_paths = ['api_docs/*', 'models/*', 'node_api.py', 'rest_api.py'] +apidoc_excluded_paths = ['docs/*', 'models/*', 'node_api.py', 'rest_api.py'] apidoc_extra_args = ['--templatedir=_templates'] apidoc_module_first = True apidoc_separate_modules = True diff --git a/pyinaturalist/api_requests.py b/pyinaturalist/api_requests.py index 9942fe3c..5ee45280 100644 --- a/pyinaturalist/api_requests.py +++ b/pyinaturalist/api_requests.py @@ -9,7 +9,6 @@ from requests import Response, Session import pyinaturalist -from pyinaturalist.api_docs import copy_signature from pyinaturalist.constants import ( MAX_DELAY, REQUESTS_PER_DAY, @@ -19,6 +18,7 @@ MultiInt, RequestParams, ) +from pyinaturalist.docs import copy_signature from pyinaturalist.request_params import prepare_request # Mock response content to return in dry-run mode diff --git a/pyinaturalist/api_docs/__init__.py b/pyinaturalist/docs/__init__.py similarity index 79% rename from pyinaturalist/api_docs/__init__.py rename to pyinaturalist/docs/__init__.py index 64879130..7cc67a3a 100644 --- a/pyinaturalist/api_docs/__init__.py +++ b/pyinaturalist/docs/__init__.py @@ -4,7 +4,8 @@ * Dynamic docs: Function signatures + docstrings based on API request params * Static docs: Sphinx documentation on readthedocs.io """ -from pyinaturalist.api_docs.forge_utils import ( +from pyinaturalist.docs.emoji import EMOJI +from pyinaturalist.docs.forge_utils import ( copy_doc_signature, copy_docstrings, copy_signature, diff --git a/pyinaturalist/docs/emoji.py b/pyinaturalist/docs/emoji.py new file mode 100644 index 00000000..ccfaf987 --- /dev/null +++ b/pyinaturalist/docs/emoji.py @@ -0,0 +1,137 @@ +"""Extended list of emoji to represent taxa""" +EMOJI = { + # Birds + 3: 'ðŸĶ', + 574: 'ðŸĶƒ', + 879: '🐔', + 71261: 'ðŸĶ…', + 6888: 'ðŸĶ†', + 1199: 'ðŸĶš', + 67569: 'ðŸĶĐ', + 2708: '🕊ïļ', + 6913: 'ðŸĶĒ', + 67564: '🐧', + 19350: 'ðŸĶ‰', + 18874: 'ðŸĶœ', + # Amphibians + reptiles + 20978: 'ðŸļ', + 26036: 'ðŸĶŽ', + 26039: '🐊', + 39532: 'ðŸĒ', + 85553: '🐍', + # Mammals + 786045: 'ðŸĩ', + 43579: 'ðŸĶ', + 846280: 'ðŸĶ§', + 47144: 'ðŸķ', + 42048: '🐚', + 42054: 'ðŸĶŠ', + 41660: 'ðŸĶ', + 41944: 'ðŸą', + 846273: 'ðŸŊ', + 43328: 'ðŸī', + 42158: 'ðŸĶŒ', + 42406: 'ðŸĶŽ', + 568826: 'ðŸŪ', + 848343: '🐷', + 568847: '🐑', + 42348: '🐐', + 846209: '🐊', + 925150: 'ðŸĶ™', + 43691: '🐘', + 43698: 'ðŸđ', + 43094: '🐰', + 45933: 'ðŸŋïļ', + 43791: 'ðŸĶŦ', + 533971: 'ðŸĶ”', + 40268: 'ðŸĶ‡', + 41636: 'ðŸŧ', + 848319: 'ðŸĶ˜', + 42981: 'ðŸĻ', + 53537: 'ðŸĶĨ', + 41770: 'ðŸĶĄ', + 526556: 'ðŸĶĶ', + 41871: 'ðŸĶĻ', + 846287: 'ðŸĶĄ', + # Fish + 47178: '🐟', + 47233: '🐠', + 47177: 'ðŸĄ', + 372843: 'ðŸĶ­', + 152871: '🐋', + 41479: '🐎', + 47273: 'ðŸĶˆ', + # Molluscs + 47115: '🐌', + 47459: '🐙', + 127352: 'ðŸĶ‘', + # Arthropods + 85493: 'ðŸĶ€', + 144114: 'ðŸĶ', + 311310: 'ðŸĶž', + 47119: '🕷ïļ', + 48894: 'ðŸĶ‚', + 172373: 'ðŸĶ‚', + 48900: 'ðŸĶ‚', + 372739: '🐛', + 144128: '🐛', + 47822: '🊰', + 153429: 'ðŸĶŸ', + 81769: 'ðŸŠģ', + 47651: 'ðŸĶ—', + 47157: 'ðŸĶ‹', + 47201: '🐝', + 47336: '🐜', + 48511: '🐜', + 47208: 'ðŸŠē', + 471714: '🐞', + # Plants + 47126: 'ðŸŒą', + 136329: 'ðŸŒē', + 47903: 'ðŸŒĩ', + 47162: 'ðŸŒū', + 121943: 'ðŸŒŋ', + 70233: '🍀', + 48866: 'ðŸŒī', + 544534: 'ðŸĨĨ', + 47605: '🌞', + 605446: 'ðŸŒŧ', + 47690: '🌚', + 48796: '🌚', + 47329: '🌷', + 47148: 'ðŸŒđ', + 47727: '🍁', + 53548: 'ðŸŒģ', + 47853: 'ðŸŒģ', + 151882: 'ðŸŒģ', + 50998: 'ðŸŒģ', + 47567: 'ðŸŒģ', + 71434: 'ðŸŒģ', + 47194: 'ðŸŒģ', + 48699: 'ðŸĨ•', + 47204: 'ðŸĨĶ', + 71291: '🍇', + 48620: '🍈', + 62910: '🍌', + 50623: '🍊', + 723302: '🍎', + 49570: '🍍', + 48874: 'ðŸĨ­', + 47351: '🍒', + 47733: 'ðŸŦ’', + 55849: '🧄', + 48516: '🍅', + 48517: 'ðŸŒķïļ', + 62848: 'ðŸĨ‘', + 635417: 'ðŸŒ―', + 55150: 'ðŸĨ', + 50299: '🍓', + 634914: 'ðŸŦ', + # Other + 1: 'ðŸū', + 47491: 'ðŸŠą', + 47170: '🍄', + 48222: 'ðŸŸĒ', + 67333: 'ðŸĶ ', + 131236: 'ðŸĶ ', +} diff --git a/pyinaturalist/api_docs/forge_utils.py b/pyinaturalist/docs/forge_utils.py similarity index 100% rename from pyinaturalist/api_docs/forge_utils.py rename to pyinaturalist/docs/forge_utils.py diff --git a/pyinaturalist/api_docs/model_docs.py b/pyinaturalist/docs/model_docs.py similarity index 100% rename from pyinaturalist/api_docs/model_docs.py rename to pyinaturalist/docs/model_docs.py diff --git a/pyinaturalist/api_docs/templates.py b/pyinaturalist/docs/templates.py similarity index 100% rename from pyinaturalist/api_docs/templates.py rename to pyinaturalist/docs/templates.py diff --git a/pyinaturalist/models/comment.py b/pyinaturalist/models/comment.py index 77e23e46..dc3a7887 100644 --- a/pyinaturalist/models/comment.py +++ b/pyinaturalist/models/comment.py @@ -6,7 +6,7 @@ @define_model class Comment(BaseModel): - """An observation comment, based on the schema of comments + """📝 An observation comment, based on the schema of comments from `GET /observations `_. """ diff --git a/pyinaturalist/models/controlled_term.py b/pyinaturalist/models/controlled_term.py index a7860ce0..51b3fe7a 100644 --- a/pyinaturalist/models/controlled_term.py +++ b/pyinaturalist/models/controlled_term.py @@ -6,7 +6,7 @@ @define_model class Annotation(BaseModel): - """An annotation, meaning a **controlled term value** applied by a **user** to an **observation**. + """📝 An annotation, meaning a **controlled term value** applied by a **user** to an **observation**. Based on the schema of annotations from `GET /observations `_. """ @@ -45,7 +45,7 @@ def __str__(self) -> str: @define_model class ControlledTermValue(BaseModel): - """A controlled term **value**, based on the schema of + """📋 A controlled term **value**, based on the schema of `GET /controlled_terms `_. """ @@ -62,7 +62,7 @@ def __str__(self): @define_model class ControlledTerm(BaseModel): - """A controlled term, based on the schema of + """📋 A controlled term, based on the schema of `GET /controlled_terms `_. """ diff --git a/pyinaturalist/models/identification.py b/pyinaturalist/models/identification.py index 9b281725..802071d0 100644 --- a/pyinaturalist/models/identification.py +++ b/pyinaturalist/models/identification.py @@ -14,7 +14,7 @@ @define_model class Identification(BaseModel): - """An observation identification, based on the schema of + """🔎 An observation identification, based on the schema of `GET /identifications `_. """ diff --git a/pyinaturalist/models/life_list.py b/pyinaturalist/models/life_list.py index 12f6fc2e..cd14cb5a 100644 --- a/pyinaturalist/models/life_list.py +++ b/pyinaturalist/models/life_list.py @@ -1,7 +1,7 @@ from itertools import groupby from typing import List -from pyinaturalist.constants import JsonResponse +from pyinaturalist.constants import JsonResponse, TableRow from pyinaturalist.models import ( Taxon, TaxonCount, @@ -14,7 +14,7 @@ @define_model class LifeListTaxon(TaxonCount): - """A single taxon in a user's life list""" + """ðŸĶ A single :py:class:`.Taxon` in a user's :py:class:`.LifeList`""" descendant_obs_count: int = field(default=0, doc='Number of observations of taxon children') direct_obs_count: int = field( @@ -26,6 +26,15 @@ def indent_level(self) -> int: """Indentation level corresponding to this item's rank level""" return int(((70 - self.rank_level) / 5)) + @property + def row(self) -> TableRow: + return { + 'ID': self.id, + 'Rank': self.rank, + 'Name': {self.name}, + 'Count': self.count, + } + def __str__(self) -> str: padding = " " * self.indent_level return f'[{self.id:<8}] {padding} {self.rank.title()} {self.name}: {self.count}' @@ -33,7 +42,7 @@ def __str__(self) -> str: @define_model_collection class LifeList(TaxonCounts): - """A user's life list, based on the schema of ``GET /observations/taxonomy``""" + """ðŸĶ✅📓 A user's life list, based on the schema of ``GET /observations/taxonomy``""" count_without_taxon: int = field(default=0) data: List[LifeListTaxon] = field(factory=list, converter=LifeListTaxon.from_json_list) # type: ignore diff --git a/pyinaturalist/models/observation.py b/pyinaturalist/models/observation.py index b97c7dcd..28fbe758 100644 --- a/pyinaturalist/models/observation.py +++ b/pyinaturalist/models/observation.py @@ -38,7 +38,7 @@ @define(auto_attribs=False, init=False, field_transformer=add_lazy_attrs) class Observation(BaseModel): - """An observation, based the schema of + """ðŸ‘Ī🔎ðŸĶ An observation, based the schema of `GET /observations `_. """ @@ -224,7 +224,7 @@ def __str__(self) -> str: @define_model_collection class Observations(BaseModelCollection): - """A collection of observations""" + """ðŸ‘Ĩ🔍ðŸĶ A collection of observations""" data: List[Observation] = field(factory=list, converter=Observation.from_json_list) diff --git a/pyinaturalist/models/observation_field.py b/pyinaturalist/models/observation_field.py index b203353f..46ba36fc 100644 --- a/pyinaturalist/models/observation_field.py +++ b/pyinaturalist/models/observation_field.py @@ -28,7 +28,7 @@ @define_model class ObservationField(BaseModel): - """An observation field **definition**, based on the schema of + """📋 An observation field **definition**, based on the schema of `GET /observation_fields `_. """ @@ -59,7 +59,7 @@ def __str__(self) -> str: @define_model class ObservationFieldValue(BaseModel): - """An observation field **value**, matching the schema of ``ofvs`` + """📝 An observation field **value**, based on the schema of ``Observation.ofvs`` from `GET /observations `_. """ diff --git a/pyinaturalist/models/photo.py b/pyinaturalist/models/photo.py index c502fc88..b2e49536 100644 --- a/pyinaturalist/models/photo.py +++ b/pyinaturalist/models/photo.py @@ -7,8 +7,10 @@ @define_model class Photo(BaseModel): - """An observation photo, based on the schema of photos from - `GET /observations `_. + """📷 An observation photo, based on the schema of photos from: + + * `GET /observations `_ + * `GET /taxa ` """ attribution: str = field(default=None, doc='License attribution') diff --git a/pyinaturalist/models/place.py b/pyinaturalist/models/place.py index 75c76b70..ab169e6f 100644 --- a/pyinaturalist/models/place.py +++ b/pyinaturalist/models/place.py @@ -20,7 +20,7 @@ def convert_optional_lat_long(obj: Union[Dict, List, None, str]): @define_model class Place(BaseModel): - """A curated or community-contributed place. Handles data from the following endpoints: + """📍 A curated or community-contributed place. Handles data from the following endpoints: * `GET /places/{id} `_ * `GET /places/nearby `_ diff --git a/pyinaturalist/models/project.py b/pyinaturalist/models/project.py index 5aa77d66..4342bfa3 100644 --- a/pyinaturalist/models/project.py +++ b/pyinaturalist/models/project.py @@ -24,7 +24,7 @@ @define_model class ProjectObservation(BaseModel): - """Metadata about an observation that has been added to a project""" + """ðŸ‘Ī🔎ðŸĶ Metadata about an observation that has been added to a project""" preferences: Dict = field(factory=dict) # Example: {'allows_curator_coordinate_access': True} project: Dict = field(factory=dict) # Example: {'id': 24237} @@ -37,7 +37,7 @@ class ProjectObservation(BaseModel): @define_model class ProjectObservationField(ObservationField): - """An :py:class:`.ObservationField` with additional project-specific information""" + """📋 An :py:class:`.ObservationField` with additional project-specific information""" project_observation_field_id: int = field(default=None) position: int = field(default=None) @@ -55,7 +55,7 @@ def from_json(cls, value: JsonResponse, **kwargs) -> 'ProjectObservationField': @define_model class ProjectUser(User): - """A :py:class:`.User` with additional project-specific information""" + """ðŸ‘Ī A :py:class:`.User` with additional project-specific information""" project_id: int = field(default=None) project_user_id: int = field(default=None) @@ -73,7 +73,7 @@ def from_json(cls, value: JsonResponse, **kwargs) -> 'ProjectUser': @define_model class Project(BaseModel): - """A dataclass containing information about a project, matching the schema of + """ðŸ‘Ĩ An iNaturalist project, based on the schema of `GET /projects `_. """ diff --git a/pyinaturalist/models/search.py b/pyinaturalist/models/search.py index 1b286d40..22f8bc44 100644 --- a/pyinaturalist/models/search.py +++ b/pyinaturalist/models/search.py @@ -10,7 +10,7 @@ @define_model class SearchResult(BaseModel): - """A dataclass for search results, matching the schema of + """🔍 A search result of any type, based on the schema of `GET /search `_. """ diff --git a/pyinaturalist/models/taxon.py b/pyinaturalist/models/taxon.py index 1c406221..3ce7a70c 100644 --- a/pyinaturalist/models/taxon.py +++ b/pyinaturalist/models/taxon.py @@ -13,6 +13,7 @@ JsonResponse, TableRow, ) +from pyinaturalist.docs import EMOJI from pyinaturalist.models import ( BaseModel, BaseModelCollection, @@ -33,10 +34,10 @@ # TODO: Include codes from other sources? Currently only including IUCN codes. @define_model class ConservationStatus(BaseModel): - """The conservation status of a taxon in a given location, based on the schema of: + """‾ïļ The conservation status of a taxon in a given location, based on the schema of: - * Taxon.conservation_status from `GET /taxa `_ - * Observation.taxon.conservation_statused from `GET /observations `_ + * ``Taxon.conservation_status`` from `GET /taxa `_ + * ``Observation.taxon.conservation_statuses`` from `GET /observations `_ """ authority: str = field(default=None, doc='Data source for conservation status') @@ -74,7 +75,7 @@ class ConservationStatus(BaseModel): @define_model class EstablishmentMeans(BaseModel): - """The establishment means for a taxon in a given location""" + """‾ïļ The establishment means for a taxon in a given location""" establishment_means: str = field( default=None, options=ESTABLISTMENT_MEANS, doc='Establishment means description' @@ -89,7 +90,7 @@ def __str__(self) -> str: @define_model class Taxon(BaseModel): - """An iNaturalist taxon, based on the schema of + """ðŸĶ An iNaturalist taxon, based on the schema of `GET /taxa `_. Can be constructed from either a full or partial JSON record. Examples of partial records @@ -202,28 +203,22 @@ def child_ids(self) -> List[int]: @property def emoji(self) -> str: - """Get an emoji representing the iconic taxon""" + """Get an emoji representing the taxon""" + for taxon_id in [self.id] + list(reversed(self.ancestor_ids)): + if taxon_id in EMOJI: + return EMOJI[taxon_id] return ICONIC_EMOJI.get(self.iconic_taxon_id, '❓') @property def full_name(self) -> str: - """Taxon rank, scientific name, and common name (if available). - - Example: - - >>> taxon.full_name - 'Genus: Physcia (Rosette Lichens)' - - """ + """Taxon rank, scientific name, common name (if available), and emoji""" if not self.name and not self.rank: return 'unknown taxon' if not self.name: - name = str(self.id) - else: - common_name = self.preferred_common_name - name = self.name + (f' ({common_name})' if common_name else '') + return f'{self.rank.title()}: {self.id}' - return f'{self.rank.title()}: {name}' + common_name = f' ({self.preferred_common_name})' if self.preferred_common_name else '' + return f'{self.emoji} {self.rank.title()}: {self.name}{common_name}' @property def icon_url(self) -> str: @@ -268,7 +263,9 @@ def __str__(self) -> str: @define_model class TaxonCount(Taxon): - """A taxon with an associated count, used in a :py:class:`.TaxonCounts` collection""" + """ðŸĶ#ïļâƒĢ A :py:class:`.Taxon` with an associated count, used in a :py:class:`.TaxonCounts` + collection + """ count: int = field(default=0, doc='Number of observations of this taxon') @@ -286,7 +283,7 @@ def row(self) -> TableRow: return { 'ID': self.id, 'Rank': self.rank, - 'Name': self.name, + 'Name': f'{self.emoji} {self.name}', 'Count': self.count, } @@ -296,7 +293,7 @@ def __str__(self) -> str: @define_model_collection class TaxonCounts(BaseModelCollection): - """A collection of taxa with an associated counts. Used with + """ðŸĶ#ïļâƒĢ📓 A collection of taxa with an associated counts. Used with `GET /observations/species_counts `_. as well as :py:class:`.LifeList`. """ diff --git a/pyinaturalist/models/user.py b/pyinaturalist/models/user.py index 9e93d989..60e33d38 100644 --- a/pyinaturalist/models/user.py +++ b/pyinaturalist/models/user.py @@ -7,7 +7,7 @@ @define_model class User(BaseModel): - """A dataclass containing information about an user, matching the schema of + """ðŸ‘Ī An iNaturalist user, based on the schema of `GET /users/{id} `_. """ diff --git a/pyinaturalist/v0/observation_fields.py b/pyinaturalist/v0/observation_fields.py index d2dc738b..ead5e47a 100644 --- a/pyinaturalist/v0/observation_fields.py +++ b/pyinaturalist/v0/observation_fields.py @@ -1,10 +1,10 @@ from typing import Any -from pyinaturalist.api_docs import document_request_params -from pyinaturalist.api_docs import templates as docs from pyinaturalist.api_requests import get, put from pyinaturalist.constants import API_V0_BASE_URL, JsonResponse from pyinaturalist.converters import convert_all_timestamps +from pyinaturalist.docs import document_request_params +from pyinaturalist.docs import templates as docs from pyinaturalist.pagination import add_paginate_all diff --git a/pyinaturalist/v0/observations.py b/pyinaturalist/v0/observations.py index 7873d88c..455976a1 100644 --- a/pyinaturalist/v0/observations.py +++ b/pyinaturalist/v0/observations.py @@ -1,8 +1,6 @@ from logging import getLogger from typing import List, Union -from pyinaturalist.api_docs import document_request_params -from pyinaturalist.api_docs import templates as docs from pyinaturalist.api_requests import delete, get, post, put from pyinaturalist.constants import ( API_V0_BASE_URL, @@ -17,6 +15,8 @@ ensure_file_obj, ensure_list, ) +from pyinaturalist.docs import document_request_params +from pyinaturalist.docs import templates as docs from pyinaturalist.exceptions import ObservationNotFound from pyinaturalist.pagination import add_paginate_all from pyinaturalist.request_params import convert_observation_fields, validate_multiple_choice_param diff --git a/pyinaturalist/v1/identifications.py b/pyinaturalist/v1/identifications.py index 73cc8988..e3249f19 100644 --- a/pyinaturalist/v1/identifications.py +++ b/pyinaturalist/v1/identifications.py @@ -1,7 +1,7 @@ -from pyinaturalist.api_docs import document_request_params -from pyinaturalist.api_docs import templates as docs from pyinaturalist.constants import JsonResponse, MultiInt from pyinaturalist.converters import convert_all_timestamps +from pyinaturalist.docs import document_request_params +from pyinaturalist.docs import templates as docs from pyinaturalist.pagination import add_paginate_all from pyinaturalist.request_params import convert_rank_range from pyinaturalist.v1 import get_v1 diff --git a/pyinaturalist/v1/observations.py b/pyinaturalist/v1/observations.py index 0be10940..a88e9a8c 100644 --- a/pyinaturalist/v1/observations.py +++ b/pyinaturalist/v1/observations.py @@ -1,5 +1,3 @@ -from pyinaturalist.api_docs import document_request_params -from pyinaturalist.api_docs import templates as docs from pyinaturalist.constants import ( NODE_OBS_ORDER_BY_PROPERTIES, HistogramResponse, @@ -12,6 +10,8 @@ convert_histogram, convert_observation_timestamps, ) +from pyinaturalist.docs import document_request_params +from pyinaturalist.docs import templates as docs from pyinaturalist.exceptions import ObservationNotFound from pyinaturalist.pagination import add_paginate_all from pyinaturalist.request_params import validate_multiple_choice_param diff --git a/pyinaturalist/v1/places.py b/pyinaturalist/v1/places.py index 19bab8b1..13e52a38 100644 --- a/pyinaturalist/v1/places.py +++ b/pyinaturalist/v1/places.py @@ -1,7 +1,7 @@ -from pyinaturalist.api_docs import document_request_params -from pyinaturalist.api_docs import templates as docs from pyinaturalist.constants import JsonResponse, MultiInt from pyinaturalist.converters import convert_all_coordinates, convert_all_place_coordinates +from pyinaturalist.docs import document_request_params +from pyinaturalist.docs import templates as docs from pyinaturalist.pagination import add_paginate_all from pyinaturalist.v1 import get_v1 diff --git a/pyinaturalist/v1/projects.py b/pyinaturalist/v1/projects.py index 71ccdcf0..ed3b4c1a 100644 --- a/pyinaturalist/v1/projects.py +++ b/pyinaturalist/v1/projects.py @@ -1,7 +1,7 @@ -from pyinaturalist.api_docs import document_request_params -from pyinaturalist.api_docs import templates as docs from pyinaturalist.constants import PROJECT_ORDER_BY_PROPERTIES, JsonResponse, MultiInt from pyinaturalist.converters import convert_all_coordinates, convert_all_timestamps +from pyinaturalist.docs import document_request_params +from pyinaturalist.docs import templates as docs from pyinaturalist.pagination import add_paginate_all from pyinaturalist.request_params import validate_multiple_choice_param from pyinaturalist.v1 import get_v1 diff --git a/pyinaturalist/v1/search.py b/pyinaturalist/v1/search.py index c5cb6ef0..25dd862e 100644 --- a/pyinaturalist/v1/search.py +++ b/pyinaturalist/v1/search.py @@ -1,7 +1,7 @@ -from pyinaturalist.api_docs import document_request_params -from pyinaturalist.api_docs import templates as docs from pyinaturalist.constants import JsonResponse from pyinaturalist.converters import convert_all_coordinates, convert_all_timestamps +from pyinaturalist.docs import document_request_params +from pyinaturalist.docs import templates as docs from pyinaturalist.v1 import get_v1 diff --git a/pyinaturalist/v1/taxa.py b/pyinaturalist/v1/taxa.py index a6de8156..1f102db7 100644 --- a/pyinaturalist/v1/taxa.py +++ b/pyinaturalist/v1/taxa.py @@ -1,7 +1,7 @@ -from pyinaturalist.api_docs import document_request_params -from pyinaturalist.api_docs import templates as docs from pyinaturalist.constants import JsonResponse, MultiInt from pyinaturalist.converters import convert_all_timestamps +from pyinaturalist.docs import document_request_params +from pyinaturalist.docs import templates as docs from pyinaturalist.pagination import add_paginate_all from pyinaturalist.request_params import convert_rank_range from pyinaturalist.v1 import get_v1 diff --git a/pyinaturalist/v1/users.py b/pyinaturalist/v1/users.py index 0a434f0d..67ce82ee 100644 --- a/pyinaturalist/v1/users.py +++ b/pyinaturalist/v1/users.py @@ -1,9 +1,9 @@ from logging import getLogger -from pyinaturalist.api_docs import document_request_params -from pyinaturalist.api_docs import templates as docs from pyinaturalist.constants import JsonResponse from pyinaturalist.converters import convert_all_timestamps, convert_generic_timestamps +from pyinaturalist.docs import document_request_params +from pyinaturalist.docs import templates as docs from pyinaturalist.v1 import get_v1 logger = getLogger(__name__) diff --git a/pyproject.toml b/pyproject.toml index 5d3eea6a..6b491a68 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,7 +83,7 @@ directory = 'test-reports' [tool.coverage.run] branch = true source = ['pyinaturalist'] -omit = ['pyinaturalist/api_docs/model_docs.py'] +omit = ['pyinaturalist/docs/model_docs.py'] [tool.isort] profile = 'black' diff --git a/test/test_forge_utils.py b/test/test_forge_utils.py index a70d8943..3a1fe52c 100644 --- a/test/test_forge_utils.py +++ b/test/test_forge_utils.py @@ -1,6 +1,6 @@ -from pyinaturalist.api_docs import copy_docstrings +from pyinaturalist.docs import copy_docstrings -# from pyinaturalist.api_docs import copy_signatures, document_request_params +# from pyinaturalist.docs import copy_signatures, document_request_params def test_document_request_params(): diff --git a/test/test_formatters.py b/test/test_formatters.py index fa8e7145..a9bd2e20 100644 --- a/test/test_formatters.py +++ b/test/test_formatters.py @@ -72,7 +72,7 @@ def test_format_identifications(input): @pytest.mark.parametrize('input', get_variations(j_observation_1)) def test_format_observation(input): expected_str = ( - '[16227955] Species: Lixus bardanae observed on 2018-09-05 14:06:00+01:00 ' + '[16227955] ðŸŠē Species: Lixus bardanae observed on 2018-09-05 14:06:00+01:00 ' 'by niconoe at 54 rue des Badauds' ) assert format_observations(input) == expected_str @@ -104,7 +104,7 @@ def test_format_places__nearby(): def test_format_search_results(): expected_str = ( - '[Taxon] [47792] Order: Odonata (Dragonflies and Damselflies)\n' + '[Taxon] [47792] 🐛 Order: Odonata (Dragonflies and Damselflies)\n' '[Place] [113562] Odonates of Peninsular India and Sri Lanka\n' '[Project] [9978] Ohio Dragonfly Survey (Ohio Odonata Survey)\n' '[User] [113886] odonatanb (Gilles Belliveau)' @@ -114,19 +114,19 @@ def test_format_search_results(): @pytest.mark.parametrize('input', get_variations(j_species_count_1)) def test_format_species_counts(input): - expected_str = '[48484] Species: Harmonia axyridis (Asian Lady Beetle): 31' + expected_str = '[48484] 🐞 Species: Harmonia axyridis (Asian Lady Beetle): 31' assert format_species_counts(input) == expected_str @pytest.mark.parametrize('input', get_variations(j_taxon_1)) def test_format_taxa__with_common_name(input): - expected_str = '[70118] Species: Nicrophorus vespilloides (Lesser Vespillo Burying Beetle)' + expected_str = '[70118] ðŸŠē Species: Nicrophorus vespilloides (Lesser Vespillo Burying Beetle)' assert format_taxa(input) == expected_str @pytest.mark.parametrize('input', get_variations(j_taxon_3_no_common_name)) def test_format_taxon__without_common_name(input): - assert format_taxa(input) == '[124162] Species: Temnostoma vespiforme' + assert format_taxa(input) == '[124162] 🊰 Species: Temnostoma vespiforme' @pytest.mark.parametrize('input', get_variations(j_user_2_partial)) diff --git a/test/test_models.py b/test/test_models.py index 5cd5093f..014df003 100644 --- a/test/test_models.py +++ b/test/test_models.py @@ -136,7 +136,7 @@ def test_identification__empty(): def test_identification__str(): identification = ID.from_json(j_identification_3) assert str(identification) == ( - '[126501311] Species: Danaus plexippus (Monarch) (improving) added on ' + '[126501311] ðŸĶ‹ Species: Danaus plexippus (Monarch) (improving) added on ' '2020-08-27 13:00:51-05:00 by samroom' )