Skip to content

Commit

Permalink
merge fix branch Bug/tests/result-set-definition-error (#9)
Browse files Browse the repository at this point in the history
* feat: definition string data type assertion

This commit modifies `words_as_str` to return a comprehensive message
upon an invalid or empty string value.

Issue: #4

Authored-by: Joshua Rose <[email protected]>

* feat(usage): GIF demonstration of tool

Thanks to gifcord.gg

Authored-by: Joshua Rose <[email protected]>

* feat(gif): add gif demo

* feat: add video to readme

* feat(docs): refactor documentation 

Add alternative installation method for windows and href to windows installation method.

Author: Joshua Rose <[email protected]>

* refactor: additional return types

Adds additional return types to functions that lack them.
Some changes to arguments in docstrings.
Omit redundant arguments

Authored-by: Joshua Rose <[email protected]>

* feat: show author with definition

This commit now shows the author with the definition.

Attempted to add function to get likes and dislikes however they are
rendered via javascript post-load so that's impossible 👽

Issue: #2

Authored-by: Joshua Rose <[email protected]>

* refactor: comment deprecated function

Comments out deprecated function for statistics that would show
deprecated text and warning.

Issue: #2
Pull Request: #8
Related commit: 7db417f

Authored-by: Joshua Rose <[email protected]>

* feat: lint and fix deprecated warning

This commit addresses various issues from tests including the deprecated
warning not being raised due to the `raise` flag being omitted / not
there.

In addition to that, theres a few pep/lint changes from my lsp.

Issue: #4

Authored-by: Joshua Rose <[email protected]>

* feat: tests for word_definition

 - adds tests cases for the word definition class
 - introduces a working pytest runner.

Issue: #4

Authored-by: Joshua Rose <[email protected]>
  • Loading branch information
H4ppy-04 authored May 24, 2023
1 parent e0b80c6 commit a4724e9
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 33 deletions.
59 changes: 52 additions & 7 deletions src/urban.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def assert_index_valid(_index: int):
raise TypeError("Index should be an integer")

if _index > 0:
PendingDeprecationWarning(
raise PendingDeprecationWarning(
"Index parameter is introduced in > 1.1.0. If you are on an eariler release this is an experimental command."
)

Expand Down Expand Up @@ -335,6 +335,42 @@ def get_statistics_from_soup(_soup: BeautifulSoup):
# print(type(x))
return;

def get_author_from_soup(_soup: BeautifulSoup) -> str:
"""Return author from soup.
:param _soup: `_soup` object as `BeautifulSoup` object.
:return: author as a string
"""

# get definition container
container = derive_definition_as_tag(_soup)

return (
container.find_next("div", class_="contributor")
.find_next("a")["href"]
.split("=")[1]
)


@deprecated("Likes and dislikes are rendered via javascript")
def get_statistics_from_soup(_soup: BeautifulSoup):
"""Return likes and dislikes (both integers) as a dictionary.
:param _soup: `_soup` object as `BeautifulSoup` object.
return: likes and dislikes (both integers) as a dictionary.
"""

# get definition container
container = derive_definition_as_tag(_soup)

x: Tag = container.find_next("div", class_="contributor").find_next_sibling(
"div"
) # pyright: ignore
print(x.find_all(name="span", recursive=True, attrs={"class": "text-xs"}))
# print(type(x))
return


# TODO get `_definition` working
def fetch_word_from_remote(_word: str) -> dict[str, str] | None:
"""Query urban dictionary for `_word`.
Expand Down Expand Up @@ -364,6 +400,9 @@ def fetch_word_from_remote(_word: str) -> dict[str, str] | None:

words_as_str = format_words_as_string_from_tag(word_meaning, hyperlinks_list)

if not isinstance(words_as_str, str) or words_as_str == "":
words_as_str = "Definition not found or not available."

# NOTE don't delete!
print(words_as_str)

Expand All @@ -372,13 +411,19 @@ def fetch_word_from_remote(_word: str) -> dict[str, str] | None:
date_posted = ""

# TODO/FIXME return date and author as well
return {"definition": "", "author": post_author, "date": date_posted}
return {"definition": words_as_str, "author": post_author, "date": date_posted}


def main():
word = join_words()

word = join_words()
# NOTE: deprecated function
# get_statistics_from_soup(get_soup_object_from_word(word))
fetch_word_from_remote(word)

# NOTE: deprecated function
# get_statistics_from_soup(get_soup_object_from_word(word))
fetch_word_from_remote(word)
print(
f"Defined by {colorama.Fore.BLUE}{get_author_from_soup(get_soup_object_from_word(word))}{colorama.Fore.RESET}"
)

print(f"Defined by {colorama.Fore.BLUE}{get_author_from_soup(get_soup_object_from_word(word))}{colorama.Fore.RESET}")
if __name__ == "__main__":
main()
75 changes: 49 additions & 26 deletions tests/test_urban.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@

from bs4 import BeautifulSoup, NavigableString, Tag

from urban import (
sys.path.insert(0, os.getcwd())

from src.urban import (
assert_index_valid,
assert_soup_and_index_valid,
derive_meaning_as_tag,
get_found_word_from_soup,
get_soup_object_from_word,
)

sys.path.insert(0, os.path.join(os.path.dirname(os.getcwd()), "src"))


class TestUrban(unittest.TestCase):
def __init__(self) -> None:
def __init__(self, methodName: str = "runTest") -> None:
self.word_index = 0
self.words = [
"YOLO",
Expand All @@ -31,18 +32,17 @@ def __init__(self) -> None:
"rickroll",
]

super().__init__()
super().__init__(methodName)

def setUp(self) -> None:
try:
self.word = self.words[self.word_index]
import random
self.word = random.choice(self.words)
print(f"[{self.words.index(self.word)}] LOOKING UP: {self.word}")
self.soup = get_soup_object_from_word(self.word)
self.word_index += 1
except IndexError:
sys.exit(0)

return super().setUp()

def test_definition_from_soup_object(self):
"""
Test definition class is present in each soup object.
Expand All @@ -67,11 +67,18 @@ def test_word_index_raises_warning(self):
Test that word index raises warning when greater than 0
"""

_soup = get_soup_object_from_word(self.word)
# NOTE This relies on there being more than 1 definition present.
with self.assertRaises(PendingDeprecationWarning):
assert_index_valid(_index=1)

def test_invalid_word_index_raises_error_from_float(self):
"""
Test invalid type in word index raises type erorr
"""

# NOTE This relies on there being more than 1 definition present.
with self.assertWarns(PendingDeprecationWarning):
assert_soup_and_index_valid(_soup, _index=1)
with self.assertRaises(TypeError):
assert_index_valid(_index=float(2.3)) # pyright: ignore

def test_word_index_raises_index_error(self):
"""
Expand All @@ -80,11 +87,8 @@ def test_word_index_raises_index_error(self):

_soup = get_soup_object_from_word(self.word)

# NOTE In order of warns / errors
with self.assertWarns(PendingDeprecationWarning) or self.assertRaises(
IndexError
):
assert_soup_and_index_valid(_soup, _index=999)
with self.assertRaises(PendingDeprecationWarning):
assert_index_valid(_index=9000000)

def test_word_type_raises_type_error(self):
"""
Expand All @@ -93,17 +97,17 @@ def test_word_type_raises_type_error(self):

_soup = get_soup_object_from_word(self.word)

assert isinstance(_soup.string, BeautifulSoup)
# assert isinstance(_soup.string, BeautifulSoup)
with self.assertRaises(TypeError):
assert_soup_and_index_valid(_soup.string, _index=0)
assert_soup_and_index_valid(_soup=False)

def test_word_none_raises_key_error(self):
def test_word_none_raises_index_error(self):
"""
Test that word raises keyerror when word is none
Test that word raises indexerror when word non-existant.
"""

with self.assertRaises(KeyError):
get_found_word_from_soup(None) # pyright: ignore
with self.assertRaises(IndexError):
get_found_word_from_soup(BeautifulSoup("test", features="lxml")) # pyright: ignore

def test_found_word_equal_to_parameter(self):
"""
Expand Down Expand Up @@ -141,6 +145,25 @@ def test_derivation_index_overload_raises_error(self):
_soup = get_soup_object_from_word(self.word)

with self.assertRaises(IndexError):
assert isinstance(
derive_meaning_as_tag(_soup, _index=999), Tag
) # pyright: ignore
assert isinstance(derive_meaning_as_tag(_soup), Tag) # pyright: ignore

def test_words_as_other_type_returns_str_error(self):
"""Test `words_as_str` returns string-based error on invalid data type output"""

def test_word_from_soup_raises_index_error(self):
"""Test that word from soup raises when a given value is missing"""

with self.assertRaises(IndexError):
_soup = get_soup_object_from_word(self.word)
word_soup = _soup.find_all_next("a")[0].select(".definintion")
word_soup_raises_key_error = word_soup[0].replace_with(
word_soup[0].get_text(strip=False)
)

assert_soup_and_index_valid(_soup)

get_found_word_from_soup(
BeautifulSoup(
word_soup_raises_key_error.get_text(strip=False), "html.parser"
)
)

0 comments on commit a4724e9

Please sign in to comment.