Commit 83497aac by Serbaf

Merge branch 'feature/testing' into develop

parents aa625633 8cf7cc0e
...@@ -89,3 +89,14 @@ Version 0.5.4: ...@@ -89,3 +89,14 @@ Version 0.5.4:
Minor fix Minor fix
Version 0.5.5: Version 0.5.5:
Implementing typings Implementing typings
0.6.0 (2019-05-16)
------------------
Main differences with last major release:
* Tweet objects do not store all the values as str anymore. The most used
fields are now attempted to cast to their type on initialization. These
improvements were added on the last versions of 0.5.x
* Tests have been added that cover most of the code in tweets.py and utils.py.
In the next versions probably even more will be added.
...@@ -51,6 +51,6 @@ setup( ...@@ -51,6 +51,6 @@ setup(
test_suite='tests', test_suite='tests',
tests_require=test_requirements, tests_require=test_requirements,
url='https://github.com/Serbaf/tweet_model', url='https://github.com/Serbaf/tweet_model',
version='0.5.5', version='0.6.0',
zip_safe=False, zip_safe=False,
) )
This source diff could not be displayed because it is too large. You can view the blob instead.
ideo,lux,batman
1,2,3
from tweet_model.tweet import Tweet
from tweet_model import utils
import pytest
import os
import datetime
#################
# FIXTURES #
#################
@pytest.fixture
def empty_tweet():
return Tweet()
@pytest.fixture
def tweet1():
return Tweet(id="128977963458933",
text="En un lugar de la Mancha...",
user__name="Julio César",
user__created_at="2019-05-01 23:54:27")
@pytest.fixture
def dict_tweet1():
dictionary_tweet1 = {}
dictionary_tweet1["id"] = 128977963458933
dictionary_tweet1["text"] = "En un lugar de la Mancha..."
dictionary_tweet1["user"] = {}
dictionary_tweet1["user"]["name"] = "Julio César"
dictionary_tweet1["user"]["created_at"] =\
datetime.datetime(2019, 5, 1, 23, 54, 27)
return dictionary_tweet1
@pytest.fixture
def csv_file_path():
current_dir = os.path.dirname(os.path.realpath(__file__))
return os.path.join(current_dir, "resources", "01.csv")
@pytest.fixture
def fake_file_path():
current_dir = os.path.dirname(os.path.realpath(__file__))
return os.path.join(current_dir, "resources", "false.csv")
##############
# TESTS #
##############
class TestTweetObjects:
def test_empty_tweet_instantiation__OK(self, empty_tweet):
"""
Check that a Tweet object can be instantiated with no values and
then all its not-nested attributes will be None (or False, since Nones
can be casted to boolean as False)
"""
for key, value in empty_tweet.__dict__.items():
if type(value) is not dict:
assert value in (None, False)
def test_nonempty_tweet_instantiation__values_OK(self, tweet1):
"""
Check some of the nested and non-nested fields after instantiating a
Tweet with some initial valid values
"""
assert tweet1.id == 128977963458933
assert tweet1.text == "En un lugar de la Mancha..."
assert tweet1["user"]["name"] == "Julio César"
assert tweet1["user"]["created_at"] ==\
datetime.datetime(2019, 5, 1, 23, 54, 27)
assert tweet1["coordinates"]["coordinates"] is None
def test_nonempty_tweet_instantiation__typing_OK(self, tweet1):
"""
Check some of the nested and non-nested fields have the right typing
"""
assert type(tweet1.id) == int
assert type(tweet1.text) == str
assert type(tweet1["user"]["name"]) == str
assert type(tweet1["user"]["created_at"]) == datetime.datetime
assert isinstance(tweet1["coordinates"]["coordinates"], type(None))
def test_get_tweet_fields_subset_OK(self, tweet1):
"""
Check that the "as_json" function returns a correct JSON representation
of the Tweet object
"""
new_dict = tweet1.get_tweet_fields_subset(["id", "text"])
assert new_dict == {"id": 128977963458933,
"text": "En un lugar de la Mancha..."}
class TestTweetUtils:
def test_get_tweet_from_csv_raw_line_OK(self, csv_file_path):
"""
Check that a Tweet object can be instantiated from a CSV file that
contains at least a header in the 1st line indicating the names of the
fields and a tweet description in the 2nd with a value for each of that
fields.
"""
with open(csv_file_path) as file_reader:
header = file_reader.readline()
tweet_contents = file_reader.readline()
tweet = utils.get_tweet_from_csv_raw_line(header, tweet_contents)
assert tweet["id"] == 1123738691938193410
def test_get_tweets_from_csv_OK(self, csv_file_path):
"""
Check that all the tweets from a CSV file can be instantiated at once
using the function "get_tweets_from_csv". Check the length of the list
so it matches the lines in the CSV and check some ids of the
instantiated tweets
"""
tweets = utils.get_tweets_from_csv(csv_file_path)
assert len(tweets) == 3214
assert tweets[3213]["id"] == 1123376500898783238
def test_get_tweets_from_csv_ERROR(self, fake_file_path):
"""
Check that, if provided with a file that doesn't correspond to a tweet
specification, an appropriate exception is raised
"""
with pytest.raises(utils.NotValidTweetError):
utils.get_tweets_from_csv(fake_file_path)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Tests for `tweet_model` package."""
import unittest
from click.testing import CliRunner
from tweet_model import tweet_model
from tweet_model import cli
class TestTweet_model(unittest.TestCase):
"""Tests for `tweet_model` package."""
def setUp(self):
"""Set up test fixtures, if any."""
def tearDown(self):
"""Tear down test fixtures, if any."""
def test_000_something(self):
"""Test something."""
def test_command_line_interface(self):
"""Test the CLI."""
runner = CliRunner()
result = runner.invoke(cli.main)
assert result.exit_code == 0
assert 'tweet_model.cli.main' in result.output
help_result = runner.invoke(cli.main, ['--help'])
assert help_result.exit_code == 0
assert '--help Show this message and exit.' in help_result.output
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Main module.""" """Main module."""
import logging
import datetime import datetime
import json import json
import pysnooper
from typing import List, Dict from typing import List, Dict
...@@ -146,7 +144,7 @@ class Tweet(): ...@@ -146,7 +144,7 @@ class Tweet():
try: try:
self.created_at =\ self.created_at =\
datetime.datetime.strptime(created_at, "%Y-%m-%d %H:%M:%S") datetime.datetime.strptime(created_at, "%Y-%m-%d %H:%M:%S")
except ValueError: except (TypeError, ValueError):
self.created_at = created_at self.created_at = created_at
try: try:
...@@ -224,7 +222,7 @@ class Tweet(): ...@@ -224,7 +222,7 @@ class Tweet():
try: try:
self.user["created_at"] = datetime.datetime.strptime( self.user["created_at"] = datetime.datetime.strptime(
user__created_at, "%Y-%m-%d %H:%M:%S") user__created_at, "%Y-%m-%d %H:%M:%S")
except ValueError: except (TypeError, ValueError):
self.user["created_at"] = user__created_at self.user["created_at"] = user__created_at
try: try:
...@@ -484,7 +482,8 @@ class Tweet(): ...@@ -484,7 +482,8 @@ class Tweet():
def get_tweet_fields_subset(self, fields: List[str]) -> Dict: def get_tweet_fields_subset(self, fields: List[str]) -> Dict:
""" """
Keep just the specified fields and return a dict Keep just the specified fields and return a dict
with just the information specified with just the information specified. Works just with non-nested fields
(nested ones can only be specified as a whole)
""" """
tweet_subset = {} tweet_subset = {}
...@@ -501,9 +500,11 @@ class Tweet(): ...@@ -501,9 +500,11 @@ class Tweet():
""" """
json_tweet = {} json_tweet = {}
for key, value in self.__dict__.items(): for key, value in self.__dict__.items():
if value is not None: if value is not None:
json_tweet[key] = value json_tweet[key] = value
return json_tweet return json_tweet
def __getitem__(self, key): def __getitem__(self, key):
......
...@@ -37,14 +37,6 @@ def get_tweet_from_csv_line(header_fields, line_fields): ...@@ -37,14 +37,6 @@ def get_tweet_from_csv_line(header_fields, line_fields):
if line_fields[i] != '': if line_fields[i] != '':
tweet_contents[header_fields[i].replace(".", "__")] =\ tweet_contents[header_fields[i].replace(".", "__")] =\
line_fields[i] line_fields[i]
# try:
# tweet = Tweet(**tweet_contents)
# except Exception as e:
# print("An error of type " + type(e).__str__ + "ocurred")
# raise Exception
#
# return tweet
return Tweet(**tweet_contents) return Tweet(**tweet_contents)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment