diff --git a/.travis.yml b/.travis.yml index 8e1e41c..72c2f56 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,10 @@ language: python -before_install: pip install -r requirements.txt +python: + - "2.7" + - "3.4" + - "3.5" + - "3.6" + - "3.7-dev" -script: nosetests \ No newline at end of file +script: python setup.py test diff --git a/packtrack/__init__.py b/packtrack/__init__.py index 80d4852..969f14b 100755 --- a/packtrack/__init__.py +++ b/packtrack/__init__.py @@ -1,6 +1,6 @@ -from correios import EncomendaRepository -from royal import RoyalMail -from dhl_gm import DhlGmTracker +from .correios import EncomendaRepository +from .royal import RoyalMail +from .dhl_gm import DhlGmTracker class Correios(object): diff --git a/packtrack/bs.py b/packtrack/bs.py new file mode 100644 index 0000000..59f2676 --- /dev/null +++ b/packtrack/bs.py @@ -0,0 +1,9 @@ +import functools + +try: + from bs4 import BeautifulSoup + BeautifulSoup = functools.partial(BeautifulSoup, features="lxml") +except ImportError: + from BeautifulSoup import BeautifulSoup + +BeautifulSoup = BeautifulSoup diff --git a/packtrack/correios.py b/packtrack/correios.py index 4514751..72a4f3c 100644 --- a/packtrack/correios.py +++ b/packtrack/correios.py @@ -15,7 +15,7 @@ def get(self, numero, auth=None): return func(numero, **kwargs) def _init_scraper(self, backend): - from scraping import CorreiosWebsiteScraper, CorreiosRastroService + from .scraping import CorreiosWebsiteScraper, CorreiosRastroService if backend is None: backend = 'www2' @@ -37,7 +37,7 @@ def adicionar_status(self, status): d = datetime self.status.append(status) t_format = self.validar_data(status.data) - self.status.sort(lambda x, y: 1 if d.strptime(x.data, t_format) > d.strptime(y.data, t_format) else -1) + self.status.sort(key=lambda x: d.strptime(x.data, t_format)) def validar_data(self, data): if re.match('^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$', data): diff --git a/packtrack/royal.py b/packtrack/royal.py index 38d2617..5032854 100644 --- a/packtrack/royal.py +++ b/packtrack/royal.py @@ -1,5 +1,6 @@ import requests -from bs4 import BeautifulSoup + +from .bs import BeautifulSoup class RoyalMail(object): diff --git a/packtrack/scraping.py b/packtrack/scraping.py index fc0c3b0..61f6f5d 100755 --- a/packtrack/scraping.py +++ b/packtrack/scraping.py @@ -1,15 +1,21 @@ import os import re -from HTMLParser import HTMLParser -from BeautifulSoup import BeautifulSoup +try: + from html.parser import HTMLParser + from html import unescape +except ImportError: + from HTMLParser import HTMLParser + unescape = None + import requests from requests.exceptions import RequestException from zeep import Client as Zeep from zeep.cache import InMemoryCache from zeep.transports import Transport -from correios import Encomenda, Status +from .bs import BeautifulSoup +from .correios import Encomenda, Status class CorreiosWebsiteScraper(object): @@ -65,6 +71,8 @@ def _text(self, value): def _get_all_status_from_html(self, html): status = [] html_parser = HTMLParser() + _unescape = unescape or html_parser.unescape + if ").*', html, re.S) @@ -80,15 +88,22 @@ def _get_all_status_from_html(self, html): except AttributeError: continue for td in tds: - content = td.renderContents().replace('\r', ' ') \ - .split('
') - class_ = td['class'] + content = td.renderContents() + content = content.replace(b'\r', b' ') + content = content.replace(b'\xa0', b' ') + content = content.replace(b'
', b'
') + content = content.split(b'
') + + # bs4 return a list, bs3 return a string, join normalize + # this behaviour + class_ = "".join(td['class']) + if class_ == 'sroDtEvent': data = '%s %s' % (content[0].strip(), content[1].strip()) local = '/'.join(self._text(content[2]).rsplit(' / ', 1)).upper() elif class_ == 'sroLbEvent': - situacao = html_parser.unescape(self._text(content[0])) - detalhes = html_parser.unescape(self._text(content[1])) + situacao = _unescape(self._text(content[0])) + detalhes = _unescape(self._text(content[1])) if detalhes: detalhes = u'%s %s' % (situacao, detalhes) status.append(Status(data=data, local=local, diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 5e0d12c..0000000 --- a/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -BeautifulSoup==3.2.1 -argparse==1.2.1 -beautifulsoup4==4.3.2 -lxml==2.3.5 -mockito==0.5.1 -requests==2.18.1 -wsgiref==0.1.2 -zeep==1.6.0 diff --git a/setup.py b/setup.py index dfbab09..9e2c60c 100755 --- a/setup.py +++ b/setup.py @@ -1,5 +1,20 @@ # coding: UTF-8 from setuptools import setup +import sys + +install_requires = [ + 'requests >= 0.14.2', + 'lxml >= 3.0.0', + 'zeep >= 1.6.0', +] +if sys.version_info >= (3, 0): + install_requires.append('beautifulsoup4 >= 4.3.2') +else: + install_requires.append('BeautifulSoup >= 3.1.0') + +tests_require = [ +] + setup( name='packtrack', @@ -12,11 +27,7 @@ keywords='encomendas track api', url='https://github.com/aleborba/packtrack', long_description='API Python para obter informacoes de encomendas. Para mais detalhes veja a documentacao no Github: https://github.com/aleborba/packtrack/blob/master/README.textile', - install_requires=[ - 'BeautifulSoup >= 3.1.0', - 'requests >= 0.14.2', - 'beautifulsoup4 >= 4.3.2', - 'lxml >= 2.3.5', - 'zeep >= 1.6.0', - ], + install_requires=install_requires, + test_suite="tests", + tests_require=tests_require, ) diff --git a/tests/correios_api_test.py b/tests/correios_api_test.py index 6777ec3..f5b62c4 100644 --- a/tests/correios_api_test.py +++ b/tests/correios_api_test.py @@ -1,7 +1,9 @@ import unittest -from mock import Mock -from mockito import when +try: + from unittest.mock import Mock +except ImportError: + from mock import Mock from packtrack import Correios @@ -10,20 +12,20 @@ class CorreiosTest(unittest.TestCase): def test_should_use_repository_to_get_encomenda(self): encomenda_repository_mock = Mock() - when(encomenda_repository_mock).get('123', auth=None) \ - .thenReturn('encomenda123') + encomenda_repository_mock.get.return_value = "encomenda123" Correios._backends[None] = encomenda_repository_mock assert Correios.track('123') == 'encomenda123' + encomenda_repository_mock.get.assert_called_with("123", auth=None) def test_service_should_receive_auth(self): auth = ('mi', 'mimi') encomenda_repository_mock = Mock() - when(encomenda_repository_mock).get('123', auth=auth) \ - .thenReturn('encomenda123') + encomenda_repository_mock.get.return_value = "encomenda123" Correios._backends['service'] = encomenda_repository_mock assert Correios.track( '123', backend='service', auth=auth) == 'encomenda123' + encomenda_repository_mock.get.assert_called_with("123", auth=auth) diff --git a/tests/correios_test.py b/tests/correios_test.py index d24712e..06b8abe 100644 --- a/tests/correios_test.py +++ b/tests/correios_test.py @@ -1,7 +1,9 @@ import unittest -from mock import Mock -from mockito import * +try: + from unittest.mock import Mock +except ImportError: + from mock import Mock from packtrack.correios import Encomenda, Status, EncomendaRepository @@ -11,8 +13,8 @@ def test_should_get_encomenda_by_numero(self): encomenda_123 = Status(data='2009-01-28 17:49:00') correios_website_scraper_mock = Mock() - when(correios_website_scraper_mock).get_encomenda_info('123', auth=None).thenReturn(encomenda_123) - + correios_website_scraper_mock.get_encomenda_info.return_value = encomenda_123 + repository = EncomendaRepository() repository.correios_website_scraper = correios_website_scraper_mock encomenda = repository.get('123') diff --git a/tests/scraping_test.py b/tests/scraping_test.py index 547c605..7aff6f3 100644 --- a/tests/scraping_test.py +++ b/tests/scraping_test.py @@ -2,7 +2,10 @@ import os import unittest -import mock +try: + from unittest import mock +except ImportError: + import mock from packtrack.scraping import CorreiosWebsiteScraper from packtrack.dhl_gm import DhlGmTracker @@ -17,9 +20,9 @@ def _assert_status(self, status, data, local, situacao, detalhes): self.assertEqual(detalhes, status.detalhes) def test_should_get_data_from_correios_website(self): - example_file = open('%s/tests/correios_website/exemplo_rastreamento_correios1.html' % os.getcwd()) - sample_html = example_file.read() - example_file.close() + filename = '%s/tests/correios_website/exemplo_rastreamento_correios1.html' % os.getcwd() + with open(filename, "rb") as f: + sample_html = f.read() http_client_mock = mock.Mock() response_mock = mock.Mock()