Skip to content

Commit

Permalink
Reduce snake to camel usage
Browse files Browse the repository at this point in the history
  • Loading branch information
stevelacey committed Nov 9, 2021
1 parent 1ef5d4f commit 4bfcd5b
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 52 deletions.
6 changes: 1 addition & 5 deletions tests/test_casing.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from worf.casing import camel_to_snake, snake_to_camel, whitespace_to_camel
from worf.casing import camel_to_snake, snake_to_camel
from worf.exceptions import NamingThingsError


Expand Down Expand Up @@ -39,7 +39,3 @@ def test_camel_to_snake_catches_invalid_chars():
def test_snake_to_camel_catches_invalid_chars():
with pytest.raises(NamingThingsError):
snake_to_camel("this_aint_no_🐍")


def test_whitespace_to_camel():
assert "thisIsAVerboseName" == whitespace_to_camel("This is a verbose name")
9 changes: 0 additions & 9 deletions worf/casing.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,3 @@ def camel_to_snake(camel):
last_was_upper = value.isupper()

return snake


def whitespace_to_camel(string):
pos = string.find(" ")
if pos == -1:
return string[:1].lower() + string[1:]

new_string = string[:pos] + string[pos + 1 :].capitalize()
return whitespace_to_camel(new_string)
23 changes: 11 additions & 12 deletions worf/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from django.utils.dateparse import parse_datetime

from worf.exceptions import NotImplementedInWorfYet
from worf.casing import snake_to_camel


class ValidationMixin:
Expand Down Expand Up @@ -36,7 +35,7 @@ def _validate_boolean(self, key):

if not isinstance(coerced, bool):
raise ValidationError(
f"Field {snake_to_camel(key)} accepts a boolean, got {value}, coerced to {coerced}"
f"Field {self.keymap[key]} accepts a boolean, got {value}, coerced to {coerced}"
)

return coerced
Expand All @@ -58,7 +57,7 @@ def _validate_datetime(self, key):

if not isinstance(coerced, datetime):
raise ValidationError(
f"Field {snake_to_camel(key)} accepts a iso datetime string, got {value}, coerced to {coerced}"
f"Field {self.keymap[key]} accepts a iso datetime string, got {value}, coerced to {coerced}"
)

return coerced
Expand All @@ -68,18 +67,18 @@ def _validate_many_to_many(self, key):

if not isinstance(value, list):
raise ValidationError(
f"Field {snake_to_camel(key)} accepts an array, got {type(value)} {value}"
f"Field {self.keymap[key]} accepts an array, got {type(value)} {value}"
)

def _validate_string(self, key, max_length):
value = self.bundle[key]

if not isinstance(value, str):
raise ValidationError(f"Field {snake_to_camel(key)} accepts string")
raise ValidationError(f"Field {self.keymap[key]} accepts string")

if max_length is not None and len(value) > max_length:
raise ValidationError(
f"Field {snake_to_camel(key)} accepts a maximum of {max_length} characters"
f"Field {self.keymap[key]} accepts a maximum of {max_length} characters"
)

return value
Expand All @@ -93,7 +92,7 @@ def _validate_int(self, key):
try:
integer = int(value)
except (TypeError, ValueError):
raise ValidationError(f"Field {snake_to_camel(key)} accepts an integer")
raise ValidationError(f"Field {self.keymap[key]} accepts an integer")

return integer

Expand All @@ -102,7 +101,7 @@ def _validate_positive_int(self, key):

if integer < 0:
raise ValidationError(
f"Field {snake_to_camel(key)} accepts a positive integer"
f"Field {self.keymap[key]} accepts a positive integer"
)

return integer
Expand All @@ -113,7 +112,7 @@ def coerce_array_of_integers(self, key):
try:
self.bundle[key] = [int(id) for id in self.bundle[key]]
except ValueError:
message = f"Field {snake_to_camel(key)} accepts an array of integers. Got {self.bundle[key]} instead."
message = f"Field {self.keymap[key]} accepts an array of integers. Got {self.bundle[key]} instead."
raise ValidationError(message + " I couldn't coerce the values.")

def validate_int(self, value):
Expand Down Expand Up @@ -167,7 +166,7 @@ def validate_bundle(self, key):
serializer = self.get_serializer()

if self.request.method in ("PATCH", "PUT") and key not in serializer.write():
message = f"{snake_to_camel(key)} is not editable"
message = f"{self.keymap[key]} is not editable"
if settings.DEBUG:
message += f":: {serializer}"
raise ValidationError(message)
Expand All @@ -179,7 +178,7 @@ def validate_bundle(self, key):
)

if not hasattr(self.model, key) and not annotation:
raise ValidationError(f"{snake_to_camel(key)} does not exist")
raise ValidationError(f"{self.keymap[key]} does not exist")

if key not in self.secure_fields and isinstance(self.bundle[key], str):
self.bundle[key] = self.bundle[key].strip()
Expand Down Expand Up @@ -231,7 +230,7 @@ def validate_bundle(self, key):
# try:
# json.loads(self.bundle[key])
# except ValueError:
# raise ValidationError(f"Field {snake_to_camel(key)} requires valid JSON")
# raise ValidationError(f"Field {self.keymap[key]} requires valid JSON")

else:
message = f"{field.get_internal_type()} has no validation method for {key}"
Expand Down
28 changes: 11 additions & 17 deletions worf/views/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from django.views.decorators.cache import never_cache
from django.utils.decorators import method_decorator

from worf.casing import camel_to_snake, whitespace_to_camel
from worf.casing import camel_to_snake, snake_to_camel
from worf.exceptions import HTTP_EXCEPTIONS, HTTP404, HTTP422, PermissionsException
from worf.serializers import LegacySerializer
from worf.validators import ValidationMixin
Expand Down Expand Up @@ -89,7 +89,8 @@ def __init__(self, *args, **kwargs):
def name(self):
if isinstance(self.payload_key, str):
return self.payload_key
return whitespace_to_camel(self.model._meta.verbose_name_plural)
verbose_name_plural = self.model._meta.verbose_name_plural
return snake_to_camel(verbose_name_plural.replace(" ", "_").lower())

def _check_permissions(self):
"""Return a permissions exception when in debug mode instead of 404."""
Expand Down Expand Up @@ -185,31 +186,24 @@ def set_bundle_from_querystring(self):
# parse_qs gives us a dictionary where all values are lists
qs = parse_qs(self.request.META["QUERY_STRING"])

# TODO: TLDR; Switch to POST for search instead of GET/querystring params.
# we want to preserve strings wherever there are not duplicate keys
# Step through the list and construct a dictionary for all fields
# that are not duplicated

# fundamentally all urlparams are treated as arrays natively.
# we can't enforce type coersion here...

# we can't assume everything is an array or everything is not an array
# when it's a querystring

raw_bundle = {}

for key, value in qs.items():
raw_bundle[key] = value[0] if len(value) == 1 else value

self.set_bundle(raw_bundle)

def set_bundle(self, raw):
def set_bundle(self, raw_bundle):
self.bundle = {}
if not raw:
self.keymap = {}

if not raw_bundle:
return # No need to loop or set self.bundle again if it's empty

for key in raw.keys():
for key in raw_bundle.keys():
field = camel_to_snake(key)
self.bundle[field] = raw[key]
self.bundle[field] = raw_bundle[key]
self.keymap[field] = key

def dispatch(self, request, *args, **kwargs):
method = request.method.lower()
Expand Down
5 changes: 1 addition & 4 deletions worf/views/create.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from django.core.exceptions import ValidationError

from worf.casing import snake_to_camel
from worf.views.base import AbstractBaseAPI


Expand All @@ -27,7 +26,5 @@ def validate(self):
# this should be moved into validate bundle
if create_fields and key not in create_fields:
raise ValidationError(
"{} not allowed when creating {}".format(
snake_to_camel(key), self.name
)
f"{self.keymap[key]} not allowed when creating {self.name}"
)
9 changes: 4 additions & 5 deletions worf/views/detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from django.db import models
from django.db.utils import IntegrityError

from worf.casing import snake_to_camel
from worf.views.base import AbstractBaseAPI


Expand Down Expand Up @@ -46,14 +45,14 @@ def set_foreign_key(self, instance, key):
else None
)
except related_model.DoesNotExist as e:
raise ValidationError(f"Invalid {snake_to_camel(key)}") from e
raise ValidationError(f"Invalid {self.keymap[key]}") from e
setattr(instance, key, related_instance)

def set_many_to_many(self, instance, key):
try:
getattr(instance, key).set(self.bundle[key])
except (IntegrityError, ValueError) as e:
raise ValidationError(f"Invalid {snake_to_camel(key)}") from e
raise ValidationError(f"Invalid {self.keymap[key]}") from e

def set_many_to_many_with_through(self, instance, key):
try:
Expand Down Expand Up @@ -83,7 +82,7 @@ def set_many_to_many_with_through(self, instance, key):
]
)
except (AttributeError, IntegrityError, ValueError) as e:
raise ValidationError(f"Invalid {snake_to_camel(key)}") from e
raise ValidationError(f"Invalid {self.keymap[key]}") from e

def update(self):
instance = self.get_instance()
Expand Down Expand Up @@ -119,7 +118,7 @@ def validate(self):
field = self.model._meta.get_field(key)

if self.bundle[key] is None and not field.null:
raise ValidationError(f"Invalid {snake_to_camel(key)}")
raise ValidationError(f"Invalid {self.keymap[key]}")


class DetailUpdateAPI(DetailAPI):
Expand Down

0 comments on commit 4bfcd5b

Please sign in to comment.