designing a pythonic interface
play

Designing a Pythonic Interface @honzakral Illustrated guide to - PowerPoint PPT Presentation

Designing a Pythonic Interface @honzakral Illustrated guide to this import this Disclaimer Personal opinions Do as I say, not as I do API API is a service for "code" Fulfills a "contract" Vaguer Simplifying Access


  1. Designing a Pythonic Interface @honzakral

  2. Illustrated guide to this

  3. import this

  4. Disclaimer Personal opinions Do as I say, not as I do

  5. API

  6. API is a service for "code"

  7. Fulfills a "contract"

  8. Vaguer

  9. Simplifying Access Simple is better than complex. Complex is better than complicated.

  10. Hiding complexity response = client.search( index="my-index", body={ "query": { "bool": { "must": [{"match": {"title": "python"}}], "must_not": [{"match": {"description": "beta"}}] "filter": [{"term": {"category": "search"}}] } }, "aggs" : { "per_tag": { "terms": {"field": "tags"}, "aggs": { "max_lines": {"max": {"field": "lines"}} } } } } ) for hit in response['hits']['hits']: print(hit['_score'], hit['_source']['title'])

  11. Hiding complexity s = Search(using=client, index="my-index") s = s.filter("term", category="search") s = s.query("match", title="python") s = s.query(~Q("match", description="beta")) s.aggs.bucket('per_tag', 'terms', field='tags') \ .metric('max_lines', 'max', field='lines') for hit in s: print(hit.meta.score, hit.title)

  12. Be explicit! Explicit is better than implicit.

  13. Hide mechanics, not meaning!

  14. Mechanics response = client.search( index="my-index", body={ "query": { "bool": { "must": [{"match": {"title": "python"}}], "must_not": [{"match": {"description": "beta"}}] "filter": [{"term": {"category": "search"}}] } }, "aggs" : { "per_tag": { "terms": {"field": "tags"}, "aggs": { "max_lines": {"max": {"field": "lines"}} } } } } ) for hit in response['hits']['hits']: print(hit['_score'], hit['_source']['title'])

  15. Meaning s = Search(using=client, index="my-index") s = s.filter("term", category="search") s = s.query("match", title="python") s = s.query(~Q("match", description="beta")) s.aggs.bucket('per_tag', 'terms', field='tags') \ .metric('max_lines', 'max', field='lines') for hit in s: print(hit.meta.score, hit.title)

  16. Admit to leakiness s = Search(using=client, index="my-index") s = s.filter("term", category="search") s = s.query("match", title="python") s = s.query(~Q("match", description="beta")) s.aggs.bucket('per_tag', 'terms', field='tags') \ .metric('max_lines', 'max', field='lines') response = client.search(index="my-index", body=s.to_dict())

  17. Be familiar! In the face of ambiguity, refuse the temptation to guess.

  18. Copy shamelessly q = Entry.objects.filter(headline__startswith="What") q = q.exclude(pub_date__gte=date.today()) q = q.filter(pub_date__gte=date.today()) curl -XGET localhost:9200/my-index/_search -d '{ "query": { "bool": { "must": [{"match": {"title": "python"}}], "must_not": [{"match": {"description": "beta"}}] "filter": [{"term": {"category": "search"}}] } }, "aggs" : { "per_tag": { "terms": {"field": "tags"}, "aggs": { "max_lines": {"max": {"field": "lines"}} } } } }'

  19. Be consistent! Special cases aren't special enough to break the rules.

  20. If it makes sense Although practicality beats purity.

  21. s = Search(using=client, index="my-index") s = s.filter("term", category="search") s = s.query("match", title="python") s = s.query(~Q("match", description="beta")) s.aggs.bucket('per_tag', 'terms', field='tags') \ .metric('max_lines', 'max', field='lines')

  22. Be friendly!

  23. Python is interactive

  24. dir, __repr__, __doc__ >>> for hit in Search().query("match", title="pycon"): ... dir(hit) ... ["meta", "title", "body", ...] >>> >>> >>> Q({ ... "bool": { ... "must": [{"match": {"title": "python"}}], ... "must_not": [{"match": {"description": "beta"}}] ... } ... }) Bool(must=[Match(title='python')], must_not=[Match(description='beta')]) >>> >>> >>> help(Search.to_dict) Help on function to_dict in module elasticsearch_dsl.search: to_dict(self, count=False, **kwargs) Serialize the search into the dictionary that will be sent over as the requests body. :arg count: a flag to specify we are interested in a body for count - no aggregations, no pagination bounds etc. All additional keyword arguments will be included into the dictionary.

  25. Iterative build Flat is better than nested. Sparse is better than dense.

  26. Iterative build s = Search(using=client, index="my-index") # filter only search s = s.filter("term", category="search") # we want python in title s = s.query("match", title="python") # and no beta releases s = s.query(~Q("match", description="beta")) # aggregate on tags s.aggs.bucket('per_tag', 'terms', field='tags') # max lines per tag s.aggs['per_tag'].metric('max_lines', 'max', field='lines')

  27. Safety is friendly Errors should never pass silently. Unless explicitly silenced.

  28. Fail by default allow ignore

  29. Tests? Tests!

  30. Be flexible! API is still code

  31. Things change Adapt!

  32. No code is perfect Now is better than never. Although never is often better than *right* now.

  33. Thanks! @honzakral

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend