Skip to content

Commit

Permalink
Just list attr options in docs instead of using validators
Browse files Browse the repository at this point in the history
  • Loading branch information
JWCook committed Jul 4, 2021
1 parent aaa764a commit 9a24ea1
Show file tree
Hide file tree
Showing 7 changed files with 19 additions and 28 deletions.
8 changes: 5 additions & 3 deletions pyinaturalist/api_docs/model_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ def get_model_classes() -> List[Type]:
# TODO: Remove autodoc member docs for LazyProperties
def get_model_doc(cls: Type) -> List[Tuple[str, str, str]]:
"""Get the name, type and description for all model attributes, properties, and LazyProperties.
If an attribute has a validator with options, include those options in the description.
If an attribute has metadata for options (possible values for the attribute), include those
options in the description.
"""

doc_rows = [_get_field_doc(field) for field in cls.__attrs_attrs__ if not field.name.startswith('_')]
Expand All @@ -70,8 +71,9 @@ def _get_field_doc(field: Attribute) -> Tuple[str, str, str]:
"""Get a row documenting an attrs Attribute"""
rtype = format_annotation(field.type)
doc = field.metadata.get('doc', '')
if getattr(field.validator, 'options', None):
options = ', '.join([f'``{opt}``' for opt in field.validator.options if opt is not None])
options = field.metadata.get('options', [])
if options:
options = ', '.join([f'``{opt}``' for opt in filter(None, options)])
doc += f'\n\n**Options:** {options}'
return (f'**{field.name}**', rtype, doc)

Expand Down
5 changes: 3 additions & 2 deletions pyinaturalist/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
define_model_collection: Callable = define(auto_attribs=False, order=False, slots=False)


def field(doc: str = '', metadata: Dict = None, **kwargs):
"""A field with extra documentation metadata"""
def field(doc: str = '', options: Iterable = None, metadata: Dict = None, **kwargs):
"""A field with extra metadata for documentation and options"""
metadata = metadata or {}
metadata['doc'] = doc
metadata['options'] = options
return attr.field(**kwargs, metadata=metadata)


Expand Down
3 changes: 1 addition & 2 deletions pyinaturalist/models/identification.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
datetime_now_field,
define_model,
field,
is_in,
)


Expand All @@ -20,7 +19,7 @@ class Identification(BaseModel):
"""

body: str = field(default=None, doc='Comment text')
category: str = field(default=None, validator=is_in(ID_CATEGORIES), doc='Identification category')
category: str = field(default=None, options=ID_CATEGORIES, doc='Identification category')
created_at: datetime = datetime_now_field(doc='Date and time the identification was added')
current: bool = field(
default=None, doc='Indicates if the identification is the currently accepted one'
Expand Down
12 changes: 3 additions & 9 deletions pyinaturalist/models/observation.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
datetime_now_field,
define_model_collection,
field,
is_in,
upper,
)
from pyinaturalist.v1 import get_observation
Expand All @@ -48,20 +47,15 @@ class Observation(BaseModel):
)
community_taxon_id: int = field(default=None, doc='The current community identification taxon')
description: str = field(default=None, doc='Observation description')
geoprivacy: str = field(
default=None, validator=is_in(GEOPRIVACY_LEVELS), doc='Location privacy level'
)
geoprivacy: str = field(default=None, options=GEOPRIVACY_LEVELS, doc='Location privacy level')
identifications_count: int = field(default=None, doc='Total number of identifications')
identifications_most_agree: bool = field(default=None, doc='Indicates if most identifications agree')
identifications_most_disagree: bool = field(
default=None, doc='Indicates if most identifications disagree'
)
identifications_some_agree: bool = field(default=None, doc='Indicates if some identifications agree')
license_code: str = field(
default=None,
converter=upper,
validator=is_in(ALL_LICENSES),
doc='Creative Commons license code',
default=None, converter=upper, options=ALL_LICENSES, doc='Creative Commons license code'
)
location: Coordinates = coordinate_pair()
mappable: bool = field(default=None, doc='Indicates if the observation can be shown on a map')
Expand All @@ -87,7 +81,7 @@ class Observation(BaseModel):
public_positional_accuracy: int = field(
default=None, doc='GPS accuracy in meters (not accurate if obscured)'
)
quality_grade: str = field(default=None, validator=is_in(QUALITY_GRADES), doc='Quality grade')
quality_grade: str = field(default=None, options=QUALITY_GRADES, doc='Quality grade')
site_id: int = field(
default=None, doc='Site ID for iNaturalist network members, or ``1`` for inaturalist.org'
)
Expand Down
8 changes: 2 additions & 6 deletions pyinaturalist/models/photo.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# TODO: Method to preview image in Jupyter
from typing import Optional, Tuple

from pyinaturalist.constants import ALL_LICENSES, CC_LICENSES, PHOTO_INFO_BASE_URL, PHOTO_SIZES, TableRow
from pyinaturalist.converters import format_dimensions, format_license
from pyinaturalist.models import BaseModel, define_model, field, is_in
from pyinaturalist.models import BaseModel, define_model, field


@define_model
Expand All @@ -14,10 +13,7 @@ class Photo(BaseModel):

attribution: str = field(default=None, doc='License attribution')
license_code: str = field(
default=None,
converter=format_license,
validator=is_in(ALL_LICENSES),
doc='Creative Commons license code',
default=None, converter=format_license, options=ALL_LICENSES, doc='Creative Commons license code'
)
original_dimensions: Tuple[int, int] = field(
converter=format_dimensions, default=(0, 0), doc='Dimensions of original image'
Expand Down
4 changes: 2 additions & 2 deletions pyinaturalist/models/search.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import List, Union

from pyinaturalist.constants import TableRow
from pyinaturalist.models import BaseModel, Place, Project, Taxon, User, define_model, field, is_in
from pyinaturalist.models import BaseModel, Place, Project, Taxon, User, define_model, field

SEARCH_RESULT_TYPES = {cls.__name__: cls for cls in [Place, Project, Taxon, User]}
SEARCH_RESULT_TITLES = {'Place': 'name', 'Project': 'title', 'Taxon': 'full_name', 'User': 'login'}
Expand All @@ -15,7 +15,7 @@ class SearchResult(BaseModel):
"""

score: float = field(default=0, doc='Search result rank')
type: str = field(default=None, validator=is_in(SEARCH_RESULT_TYPES), doc='Search result type')
type: str = field(default=None, options=SEARCH_RESULT_TYPES, doc='Search result type')
matches: List[str] = field(factory=list, doc='Search terms matched')
record: SearchResultRecord = field(default=None, doc='Search result object')

Expand Down
7 changes: 3 additions & 4 deletions pyinaturalist/models/taxon.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
define_model,
define_model_collection,
field,
is_in,
upper,
)
from pyinaturalist.v1 import get_taxa_by_id
Expand Down Expand Up @@ -52,7 +51,7 @@ class ConservationStatus(BaseModel):
status: str = field(
default=None,
converter=upper,
validator=is_in(CONSERVATION_STATUSES),
options=CONSERVATION_STATUSES,
doc='Short code for conservation status',
)
status_name: str = field(default=None, doc='Full name of conservation status')
Expand All @@ -78,7 +77,7 @@ class EstablishmentMeans(BaseModel):
"""The establishment means for a taxon in a given location"""

establishment_means: str = field(
default=None, validator=is_in(ESTABLISTMENT_MEANS), doc='Establishment means description'
default=None, options=ESTABLISTMENT_MEANS, doc='Establishment means description'
)
place: property = LazyProperty(
Place.from_json_list, type=Place, doc='Location that the establishment means applies to'
Expand Down Expand Up @@ -143,7 +142,7 @@ class Taxon(BaseModel):
default=None,
doc='Number indicating rank level, for easier comparison between ranks (kingdom=higest)',
)
rank: str = field(default=None, validator=is_in(RANKS), doc='Taxon rank')
rank: str = field(default=None, options=RANKS, doc='Taxon rank')
taxon_changes_count: int = field(default=None, doc='Number of curator changes to this taxon')
taxon_schemes_count: int = field(default=None, doc='Taxon schemes that include this taxon')
wikipedia_summary: str = field(
Expand Down

0 comments on commit 9a24ea1

Please sign in to comment.