-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
linting (automatic and manual) + pre-commit #2
base: main
Are you sure you want to change the base?
Conversation
|
||
# TODO: Build out additional endpoints | ||
|
||
# /regulations | ||
|
||
# /instruments | ||
|
||
# /analytes | ||
|
||
# /instruments | ||
|
||
# /lab_results | ||
|
||
# Optional: Find a way to generalize | ||
# path("v1/<slug:endpoint>/", views.get_labs, name="endpoint"), | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah that's a shame. if you want these back in, I can add comments on the blank lines for placeholders.
Awesome for jumping right in @mathematicalmichael, linting is definitely needed. I will review this today. Just a heads up, I've consolidated the API code (for now) into the main Cannlytics platform. As it's simply a Django app, it can be decoupled and run in a separate container if needed. Simply to speed up development I condensed the code base into 1 repository. The API is functional for development in this repository, but you may want to work in the main repository for the time being. This repository may be updated in the future to contain a standalone implementation of the API. Thank you again, |
Word! Would you be interested in this kind of PR on the other repo? I did notice it was more active but didn't know what to make of that. Appreciate the explanation. |
Definitely, let me explore the linting in this repository first, just don't want to add anything that may trip up the publishing process. This is the next task on my plate. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey Michael I am a fan of linting, so thank you for adding this. There are 2 main project-specific code style choices that have been made that conflict with the style enforced by Black:
- Apostrophes are preferred quotations for readability and speed of writing.
- A new line at the end of files is preferred to stay consistent with style across file types (i.e. all files should end in a new line, regardless of type). This is inline with the Python philosophy that there should be preferably 1 way to do something and special cases are not special enough to break the rules.
Other than these 2 main conflicts, Black does catch some fixes that need to be made, such as extra spaces, etc.
So, long story short, for my sake it would be a smaller change if you were able to ignore these 2 rules or make a request with specific style fixes, such as removing extraneous spaces.
Please let me know your thoughts and if I'm missing something. I definitely want to get your contribution committed.
Thank you and talk with you soon,
Keegan
yeahhh I prefer the apostrophes too. I write with them and let the autolinting take care of it as an after thought. |
here's their rationale: https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html let me know what you think. I dont care much, I type single ones while developing, and lint at the end. there does seem to be an option to skip string normalization. |
Thanks for looking into this. There appears to be an option to ignore single quotes. Perhaps we can try that and see if that would make adopting Black a smaller change. Would you mind exploring this option? Otherwise I can take a look tomorrow. Thank you for exploring this, it is going to be important to standardize the project to help with adoption. Would you want to explore the option described below if you have time? If you are adopting Black in a large project with pre-existing string conventions (like the popular “single quotes for data, double quotes for human-readable strings”), you can pass |
@keeganskeate yeah I can try that but what do you think about the philosophy of "type single quotes, develop as you wish, and then let the formatter take care of linting?" unfortunately I didn't stage the commits in pieces that would make reverting black easy (precommit was configured to not allow me to commit without black passing first, didn't think to disable that and commit that change first... but def noted for future attempts!!!), and did fix a number of linting errors manually. So I just want to make sure you're definitely sure that you want single quotes before re-doing the linting. That would look like: try a find/replace for all quotes to single, re-run black with that flag, and then manually review the diff to see if there were any double quotes that changed incorrectly. |
Hey @mathematicalmichael , I don't have the strongest preference one way or the other (as long as the code runs!). I do have a slight preference for reading single quotes. I have been waffling over which to adopt, so if you have strong preferences then we can consider picking one. If you don't mind, then smaller commits would be easier to review. I apologize that you may have to re-do some of the work. A good portion of the linting was helpful, so please see if there is a way that your work can be salvaged and merged in some manner. So, perhaps start a new branch (not necessarily) and commit a handful of the changes and I can likely get everything merged. My apologies for the slow down, just want to make sure everything can get reviewed and merged into the project smoothly. Thank you for your hard work. P.S. I do think you may want to end up working in the main repository before too long, but please keep steamrolling wherever you are most comfortable. |
@keeganskeate ran those |
""" Identify the user's Firebase account using an ID token. """ | ||
authorization = request.headers["Authorization"] | ||
"""Identify the user's Firebase account using an ID token.""" | ||
authorization = request.headers['Authorization'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@keeganskeate preference?
|
||
Resources: | ||
|
||
""" | ||
import os | ||
import requests | ||
|
||
BASE = "http://127.0.0.1:4200/" | ||
BASE = 'http://127.0.0.1:4200/' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BASE = 'http://127.0.0.1:4200/' | |
BASE = "http://127.0.0.1:4200/" |
BASE = 'http://127.0.0.1:4200/' | ||
ENDPOINTS = ['', '/labs'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BASE = 'http://127.0.0.1:4200/' | |
ENDPOINTS = ['', '/labs'] | |
BASE = "http://127.0.0.1:4200/" | |
ENDPOINTS = ["", "/labs"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@keeganskeate how do you want to handle this?
</urlset> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
</urlset> | |
</urlset> | |
Sitemap: https://www.api.cannlytics.com/sitemap.xml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sitemap: https://www.api.cannlytics.com/sitemap.xml | |
Sitemap: https://www.api.cannlytics.com/sitemap.xml | |
# "--", "python", "manage.py", "collectstatic", "--no-input"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# "--", "python", "manage.py", "collectstatic", "--no-input"] | |
# "--", "python", "manage.py", "collectstatic", "--no-input"] | |
|
||
|
||
def create_reference(database, reference): | ||
"""Create a database reference for a given path.""" | ||
ref = database | ||
parts = reference.split('/') | ||
parts = reference.split("/") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parts = reference.split("/") | |
parts = reference.split('/') |
@@ -31,7 +31,7 @@ def create_reference(database, reference): | |||
|
|||
def get_keywords(string): | |||
"""Get keywords for a given string.""" | |||
keywords = string.lower().split(' ') | |||
keywords = string.lower().split(" ") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keywords = string.lower().split(" ") | |
keywords = string.lower().split(' ') |
collection = collection.where( | ||
filter["key"], filter["operation"], filter["value"] | ||
) | ||
if order_by and desc: | ||
collection = collection.order_by(order_by, direction='DESCENDING') | ||
collection = collection.order_by(order_by, direction="DESCENDING") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@keeganskeate mixed usage again.
Do you want these single or double?
|
||
|
||
def create_account(name, email, notification=True): | ||
""" | ||
Given user name and email, create an account if the email isn't being used | ||
by an existing account. | ||
""" | ||
chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$-_' | ||
chars = "abcdefghijklmnopqrstuvwxyz0123456789!@#$-_" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chars = "abcdefghijklmnopqrstuvwxyz0123456789!@#$-_" | |
chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$-_' |
print( | ||
"File {} uploaded to {}.".format( | ||
source_file_name, destination_blob_name | ||
) | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually prefer this older style but black
does not... =/
message = 'Welcome to the Cannlytics API.' | ||
message += f'The current version is {VERSION} and is located at {BASE}/{VERSION}.' | ||
return Response({'data': message}, content_type='application/json') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
preference here?
message += f'{endpoint}\n' | ||
return Response({'data': message}, content_type='application/json') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
message += f'{endpoint}\n' | |
return Response({'data': message}, content_type='application/json') | |
message += f"{endpoint}\n" | |
return Response({"data": message}, content_type="application/json") |
message = f'Welcome to {VERSION} of the Cannlytics API.' | ||
message += 'Available endpoints:\n\n' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
message = f'Welcome to {VERSION} of the Cannlytics API.' | |
message += 'Available endpoints:\n\n' | |
message = f"Welcome to {VERSION} of the Cannlytics API." | |
message += "Available endpoints:\n\n" |
review leaves a lot of clarifications required. feel free to commit suggestions. |
limit = request.query_params.get("limit", None) | ||
order_by = request.query_params.get("order_by", "state") | ||
# TODO: Get any filters from dict(request.query_params) | ||
labs = get_collection('labs', order_by=order_by, limit=limit, filters=[]) | ||
return Response({ "data": labs}, content_type="application/json") | ||
labs = get_collection("labs", order_by=order_by, limit=limit, filters=[]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
labs = get_collection("labs", order_by=order_by, limit=limit, filters=[]) | |
labs = get_collection('labs', order_by=order_by, limit=limit, filters=[]) |
@@ -29,17 +29,19 @@ def labs(request, format=None): | |||
limit = request.query_params.get("limit", None) | |||
order_by = request.query_params.get("order_by", "state") | |||
# TODO: Get any filters from dict(request.query_params) | |||
labs = get_collection('labs', order_by=order_by, limit=limit, filters=[]) | |||
return Response({ "data": labs}, content_type="application/json") | |||
labs = get_collection("labs", order_by=order_by, limit=limit, filters=[]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
usage on line 90 uses double quotes, assuming that was the intent. leaving this
@@ -1,23 +1,26 @@ | |||
from rest_framework import status | |||
# from rest_framework import status |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# from rest_framework import status |
from rest_framework.decorators import api_view | ||
from rest_framework.response import Response | ||
|
||
from utils.firebase import get_collection, get_document, update_document | ||
# from utils.firebase import get_collection, get_document, update_document |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# from utils.firebase import get_collection, get_document, update_document |
|
||
|
||
@api_view(['GET', 'POST']) | ||
def lab_results(request, format=None): | ||
"""Get lab results data.""" | ||
|
||
if request.method == 'GET': | ||
limit = request.query_params.get("limit", 1000) | ||
limit = request.query_params.get('limit', 1000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
limit = request.query_params.get('limit', 1000) | |
limit = request.query_params.get("limit", 1000) |
if limit: | ||
limit = int(limit) | ||
order_by = request.query_params.get("order_by", "") | ||
order_by = request.query_params.get('order_by', '') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
order_by = request.query_params.get('order_by', '') | |
order_by = request.query_params.get("order_by", "") |
docs = get_collection( | ||
'tests/leaf/lab_results', order_by=order_by, limit=limit, filters=[] | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like I recall another get_collection
with double quotes.
@@ -28,12 +31,13 @@ def mmes(request, format=None): | |||
"""Get licensee (MME) data.""" | |||
|
|||
if request.method == 'GET': | |||
limit = request.query_params.get("limit", None) | |||
limit = request.query_params.get('limit', None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
limit = request.query_params.get('limit', None) | |
limit = request.query_params.get("limit", None) |
if limit: | ||
limit = int(limit) | ||
order_by = request.query_params.get("order_by", "") | ||
order_by = request.query_params.get('order_by', '') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
order_by = request.query_params.get('order_by', '') | |
order_by = request.query_params.get("order_by", "") |
from datetime import datetime | ||
from rest_framework import status | ||
|
||
# from rest_framework import status |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# from rest_framework import status |
|
||
# from .auth import authenticate | ||
# from utils.firebase import get_document, update_document |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# from .auth import authenticate | |
# from utils.firebase import get_document, update_document |
|
||
|
||
@api_view(['GET']) | ||
def base(request, format=None): | ||
"""Informational version endpoint.""" | ||
message = f"Welcome to {VERSION} of the Cannlytics API. Available endpoints:\n\n" | ||
message = f'Welcome to {VERSION} of the Cannlytics API. Available endpoints:\n\n' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
message = f'Welcome to {VERSION} of the Cannlytics API. Available endpoints:\n\n' | |
message = f"Welcome to {VERSION} of the Cannlytics API. Available endpoints:\n\n" |
message += f'{endpoint}\n' | ||
return Response({'message': message}, content_type='application/json') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
message += f'{endpoint}\n' | |
return Response({'message': message}, content_type='application/json') | |
message += f"{endpoint}\n" | |
return Response({"message": message}, content_type="application/json") |
print("Getting user...") | ||
# limit = request.query_params.get("limit", None) | ||
# order_by = request.query_params.get("order_by", "state") | ||
print('Getting user...') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
print('Getting user...') | |
print("Getting user...") |
# limit = request.query_params.get('limit', None) | ||
# order_by = request.query_params.get('order_by', 'state') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# limit = request.query_params.get('limit', None) | |
# order_by = request.query_params.get('order_by', 'state') | |
# limit = request.query_params.get("limit", None) | |
# order_by = request.query_params.get("order_by", "state") |
# # TODO: Get any filters from dict(request.query_params) | ||
# labs = get_collection('labs', order_by=order_by, limit=limit, filters=[]) | ||
user = {} | ||
return Response({ "data": user}, content_type="application/json") | ||
return Response({'data': user}, content_type='application/json') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return Response({'data': user}, content_type='application/json') | |
return Response({"data": user}, content_type="application/json") |
|
||
# Update or create user(s). | ||
elif request.method == 'POST': | ||
print("Creating a user...") | ||
return Response({ "success": True}, content_type="application/json") | ||
print('Creating a user...') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
print('Creating a user...') | |
print("Creating a user...") |
print("Creating a user...") | ||
return Response({ "success": True}, content_type="application/json") | ||
print('Creating a user...') | ||
return Response({'success': True}, content_type='application/json') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return Response({'success': True}, content_type='application/json') | |
return Response({"success": True}, content_type="application/json") |
limit = request.query_params.get('limit', None) | ||
order_by = request.query_params.get('order_by', 'state') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
limit = request.query_params.get('limit', None) | |
order_by = request.query_params.get('order_by', 'state') | |
limit = request.query_params.get("limit", None) | |
order_by = request.query_params.get("order_by", "state") |
ugh yeah... this wasn't a great idea. I think if you want to adopt since this repo isn't in use, might as well close this out but re-try on the real repo with the |
pip install pre-commit black flake8
and you're off to the races. no commits will ever contain unlinted code again. just set this up on cafelytics yesterday and wanted to practice on another project so I wouldn't forget the process of setting it up... figured I'd multitask and explore your api while doing so.set up process (after installing the three packages above):
create the pre-commit yaml config file, pieced together for python relevant stuff but not too intrusive, just the basics.
pre-commit install
pre-commit run --all
then manual linting + checking with
flake8
after auto-formatting withblack
.didn't go so far as to define development dependencies because I didn't want to add a
setup.cfg/py
file at this stage. think you only need to runpre-commit install
once in your local dev environment.