Skip to content
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

FedericoDominguez's Submission ⭐ #40

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
#
# Read more on Dockerfile best practices at the source:
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices
RUN apt-get update && apt-get install -y --no-install-recommends postgresql-client nodejs
RUN apt-get update && apt-get install -y --no-install-recommends postgresql-client nodejs npm

# Inside the container, create an app directory and switch into it
RUN mkdir /app
Expand Down
66 changes: 66 additions & 0 deletions parserator_web/static/js/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,68 @@
/* TODO: Flesh this out to connect the form to the API and render results
in the #address-results div. */

// Adding event listeners
document.addEventListener("DOMContentLoaded", function () {
var form = document.getElementById("address-form");

form.addEventListener("submit", async function (e) {
e.preventDefault();

// Declaring variables
var address = document.getElementById("address").value;
var url = "/api/parse/";
var queryParams = new URLSearchParams({ address: address });

try {
var response = await fetch(`${url}?${queryParams}`, {
method: 'GET'
});

var contentData = await response.json();

if (!response.ok) {
throw new Error(contentData.detail || contentData.error);
}

displayResults(contentData);
} catch (error) {
displayError(error.message);
}
});

function displayResults(data) {
document.getElementById("error-results").style.display = "none";
var resultsDiv = document.getElementById("address-results");
resultsDiv.style.display = "block";

document.getElementById("parse-type").textContent = data.address_type;

var tableBody = document.querySelector("#address-results-table tbody");
tableBody.innerHTML = '';

// Creating table
for (var [key, value] of Object.entries(data.address_components)) {
var row = document.createElement("tr");
var partCell = document.createElement("td");
var tagCell = document.createElement("td");

partCell.textContent = key;
tagCell.textContent = value;

row.appendChild(partCell);
row.appendChild(tagCell);

tableBody.appendChild(row);
}
}

function displayError(errorMessage) {
document.getElementById("address-results").style.display = "none";

var errorDiv = document.getElementById("error-results");
errorDiv.style.display = "block";

document.getElementById("parse-error").textContent = errorMessage;
}
});

9 changes: 6 additions & 3 deletions parserator_web/templates/parserator_web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,21 @@ <h3 id="usaddress-parser"><i class="fa fa-fw fa-map-marker-alt"></i> U.S. addres
<p>Dealing with some messy or unstructured addresses? We can parse them for you.</p>
<div class="card card-body bg-light">
<p><strong>Try it out!</strong> Parse an address in the United States into fields like <code>AddressNumber</code>, <code>StreetName</code> and <code>ZipCode</code>.</p>
<form class="form" role="form">
<form id="address-form" class="form" role="form">
{% csrf_token %}
<input name="address" type="text" class="form-control" id="address" placeholder="123 Main St. Suite 100 Chicago, IL">
<button id="submit" type="submit" class="btn btn-success mt-3">Parse!</button>
</form>
</div>
<!-- TODO: Display parsed address components here. -->

<div id="error-results", style="display:none;">
<p id="parse-error"></p>
</div>
<div id="address-results" style="display:none">
<h4>Parsing results</h4>
<p>Address type: <strong><span id="parse-type"></span></strong></p>
<table class="table table-bordered">
<table id="address-results-table" class="table table-bordered">
<thead>
<tr>
<th>Address part</th>
Expand All @@ -36,7 +40,6 @@ <h4>Parsing results</h4>
</div>
</div>
{% endblock %}

{% block extra_js %}
<script src="{% static 'js/index.js' %}"></script>
{% endblock %}
71 changes: 69 additions & 2 deletions parserator_web/views.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,91 @@
import usaddress
from django.views.generic import TemplateView
from http import HTTPStatus
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.renderers import JSONRenderer
from rest_framework.exceptions import ParseError


class Home(TemplateView):
template_name = 'parserator_web/index.html'
template_name = "parserator_web/index.html"


class AddressParse(APIView):
renderer_classes = [JSONRenderer]

def get(self, request):
"""
Extracts the address from the get request
"""
# TODO: Flesh out this method to parse an address string using the
# parse() method and return the parsed components to the frontend.
return Response({})

address = request.GET.get("address")
try:
parsed_address, address_type = self.parse(address)
response = Response(
{
"input_string": address,
"address_components": parsed_address,
"address_type": address_type,
},
)

except usaddress.RepeatedLabelError:
response = Response(
{
"input_string": address,
"address_components": {},
"address_type": "",
"error": "Remove repeated labels before parsing",
},
status=HTTPStatus.BAD_REQUEST,
)

except ParseError as error:
response = Response(
{
"input_string": address,
"address_components": {},
"address_type": "",
"error": str(error),
},
status=HTTPStatus.BAD_REQUEST,
)

except Exception as error:
response = Response(
{
"input_string": address,
"address_components": {},
"address_type": "",
"error": f"Unknown error: {error}",
},
status=HTTPStatus.INTERNAL_SERVER_ERROR,
)

return response

def parse(self, address):
"""
Uses the usaddress package to parse the address
"""
# TODO: Implement this method to return the parsed components of a
# given address using usaddress: https://github.com/datamade/usaddress

if not address:
raise ParseError("Address can not be empty")

# Catch error and raise it as ParseError
parsed_address = usaddress.parse(address)
address_type = usaddress.tag(address)

address_components = {}

for element in parsed_address:
address_components[element[1]] = element[0]

address_type = address_type[-1]

return address_components, address_type
54 changes: 45 additions & 9 deletions tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,51 @@
import pytest
""""""

from http import HTTPStatus

PARSE_API = "/api/parse/"


def test_api_parse_succeeds(client):
# TODO: Finish this test. Send a request to the API and confirm that the
# data comes back in the appropriate format.
address_string = '123 main st chicago il'
pytest.fail()
"""
Tests the API by sending an address
"""
address_string = "123 main st chicago il"
correct_answer = {
"AddressNumber": "123",
"StreetName": "main",
"StreetNamePostType": "st",
"PlaceName": "chicago",
"StateName": "il",
}

correct_address_type = "Street Address"

payload = {"address": address_string}

# Invoking API and getting response contents
response = client.get(PARSE_API, payload)
address_type = response.json()["address_type"]
components = response.json()["address_components"]

assert response.status_code == HTTPStatus.OK
assert address_type == correct_address_type
assert components == correct_answer


def test_api_parse_raises_error(client):
# TODO: Finish this test. The address_string below will raise a
# RepeatedLabelError, so ParseAddress.parse() will not be able to parse it.
address_string = '123 main st chicago il 123 main st'
pytest.fail()
"""
Verify API raises an error
"""

address_string = "123 main st chicago il 123 main st"

payload = {"address": address_string}

# Invoking API and getting response contents
response = client.get(PARSE_API, payload)
address_type = response.json()["address_type"]
error = response.json()["error"]

assert response.status_code == HTTPStatus.BAD_REQUEST
assert address_type == ""
assert error is not None