Source code for cartolafc.api

# -*- coding: utf-8 -*-

import logging
import sys

import requests

from cartolafc.decorators import RequiresAuthentication
from cartolafc.error import CartolaFCError, CartolaFCOverloadError
from cartolafc.models import Atleta, Clube, DestaqueRodada, Liga, LigaPatrocinador, Mercado, PontuacaoInfo, Time
from cartolafc.models import TimeInfo
from cartolafc.util import convert_team_name_to_slug, parse_and_check_cartolafc

logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)

if sys.version_info < (2, 7, 9):
    requests.packages.urllib3.disable_warnings()

MERCADO_ABERTO = 1
MERCADO_FECHADO = 2

CAMPEONATO = 'campeonato'
TURNO = 'turno'
MES = 'mes'
RODADA = 'rodada'
PATRIMONIO = 'patrimonio'


[docs]class Api(object): """ Uma API em Python para o Cartola FC Exemplo de uso: Para criar uma instância da classe cartolafc.Api, sem autenticação: >>> import cartolafc >>> api = cartolafc.Api() Para obter o status atual do mercado >>> mercado = api.mercado() >>> print(mercado.rodada_atual, mercado.status.nome) Para utilizar autenticação, é necessário instancias a classe cartolafc.Api com os argumentos email e senha. >>> api = cartolafc.Api(email='usuario@email.com', password='s3nha') Para obter os dados de uma liga (após se autenticar), onde "nome" é o nome da liga que deseja buscar: >>> liga = api.liga(nome) >>> print(liga.nome) python-cartolafc é massa!!! E possui muitos outros métodos, como: >>> api.mercado() >>> api.time(nome, slug) >>> api.busca_times(termo) """ def __init__(self, email=None, password=None, attempts=1, json=False): """ Instancia um novo objeto de cartolafc.Api. Args: email (str): O e-mail da sua conta no CartolaFC. Requerido se o password for informado. password (str): A senha da sua conta no CartolaFC. Requerido se o email for informado. attempts (int): Quantidade de tentativas que serão efetuadas se os servidores estiverem sobrecarregados. json (bool): True se desejar receber as respostas da API no formato JSON. Obs: Não são todos os serviços que suportam o retorno no formato JSON Raises: cartolafc.CartolaFCError: Se as credenciais forem inválidas ou se apenas um dos dois argumentos (email e password) for informado. """ self._api_url = 'https://api.cartolafc.globo.com' self._auth_url = 'https://login.globo.com/api/authentication' self._email = email self._password = password self._glb_id = None self.attempts = attempts if isinstance(attempts, int) and attempts > 0 else 1 self.json = bool(json) if bool(email) != bool(password): raise CartolaFCError('E-mail ou senha ausente') elif all((email, password)): self.set_credentials(email, password)
[docs] def set_credentials(self, email, password): """ Realiza a autenticação no sistema do CartolaFC utilizando o email e password informados. Args: email (str): O email do usuário password (str): A senha do usuário Raises: cartolafc.CartolaFCError: Se o conjunto (email, password) não conseguiu realizar a autenticação com sucesso. """ self._email = email self._password = password response = requests.post(self._auth_url, json=dict(payload=dict(email=self._email, password=self._password, serviceId=4728))) body = response.json() if response.status_code == 200: self._glb_id = body['glbId'] else: raise CartolaFCError(body['userMessage'])
@RequiresAuthentication def amigos(self): url = '{api_url}/auth/amigos'.format(api_url=self._api_url) data = self._request(url) return [TimeInfo.from_dict(time_info) for time_info in data['times']] @RequiresAuthentication def liga(self, nome=None, slug=None, page=1, order_by=CAMPEONATO): """ Este serviço requer que a API esteja autenticada, e realiza uma busca pelo nome ou slug informados. Este serviço obtém apenas 20 times por página, portanto, caso sua liga possua mais que 20 membros, deve-se utilizar o argumento "page" para obter mais times. Args: nome (str): Nome da liga que se deseja obter. Requerido se o slug não for informado. slug (str): Slug do time que se deseja obter. *Este argumento tem prioridade sobre o nome* page (int): Página dos times que se deseja obter. order_by (str): É possível obter os times ordenados por "campeonato", "turno", "mes", "rodada" e "patrimonio". As constantes estão disponíveis em "cartolafc.CAMPEONATO", "cartolafc.TURNO" e assim sucessivamente. Returns: Um objeto representando a liga encontrada. Raises: CartolaFCError: Se a API não está autenticada ou se nenhuma liga foi encontrada com os dados recebidos. """ if not any((nome, slug)): raise CartolaFCError('Você precisa informar o nome ou o slug da liga que deseja obter') slug = slug if slug else convert_team_name_to_slug(nome) url = '{api_url}/auth/liga/{slug}'.format(api_url=self._api_url, slug=slug) data = self._request(url, params=dict(page=page, orderBy=order_by)) return Liga.from_dict(data, order_by) @RequiresAuthentication def pontuacao_atleta(self, id): url = '{api_url}/auth/mercado/atleta/{id}/pontuacao'.format(api_url=self._api_url, id=id) data = self._request(url) return [PontuacaoInfo.from_dict(pontuacao_info) for pontuacao_info in data] @RequiresAuthentication def time_logado(self): url = '{api_url}/auth/time'.format(api_url=self._api_url) data = self._request(url) clubes = {clube['id']: Clube.from_dict(clube) for clube in data['clubes'].values()} return Time.from_dict(data, clubes=clubes) def clubes(self): url = '{api_url}/clubes'.format(api_url=self._api_url) data = self._request(url) return {int(clube_id): Clube.from_dict(clube) for clube_id, clube in data.items()}
[docs] def ligas(self, query): """ Retorna o resultado da busca ao Cartola por um determinado termo de pesquisa. Args: query (str): Termo para utilizar na busca. Returns: Uma lista de instâncias de cartolafc.Liga, uma para cada liga contento o termo utilizado na busca. """ url = '{api_url}/ligas'.format(api_url=self._api_url) data = self._request(url, params=dict(q=query)) return [Liga.from_dict(liga_info) for liga_info in data]
def ligas_patrocinadores(self): url = '{api_url}/patrocinadores'.format(api_url=self._api_url) data = self._request(url) return {int(patrocinador_id): LigaPatrocinador.from_dict(patrocinador) for patrocinador_id, patrocinador in data.items()}
[docs] def mercado(self): """ Obtém o status do mercado na rodada atual. Returns: Uma instância de cartolafc.Mercado representando o status do mercado na rodada atual. """ url = '{api_url}/mercado/status'.format(api_url=self._api_url) data = self._request(url) return Mercado.from_dict(data)
def mercado_atletas(self): url = '{api_url}/atletas/mercado'.format(api_url=self._api_url) data = self._request(url) clubes = {clube['id']: Clube.from_dict(clube) for clube in data['clubes'].values()} return [Atleta.from_dict(atleta, clubes=clubes) for atleta in data['atletas']]
[docs] def parciais(self): """ Obtém um mapa com todos os atletas que já pontuaram na rodada atual (aberta). Returns: Uma mapa, onde a key é um inteiro representando o id do atleta e o valor é uma instância de cartolafc.Atleta Raises: CartolaFCError: Se o mercado atual estiver com o status fechado. """ if self.mercado().status.id == MERCADO_FECHADO: url = '{api_url}/atletas/pontuados'.format(api_url=self._api_url) data = self._request(url) clubes = {clube['id']: Clube.from_dict(clube) for clube in data['clubes'].values()} return {int(atleta_id): Atleta.from_dict(atleta, clubes=clubes, atleta_id=int(atleta_id)) for atleta_id, atleta in data['atletas'].items()} raise CartolaFCError('As pontuações parciais só ficam disponíveis com o mercado fechado.')
def pos_rodada_destaques(self): if self.mercado().status.id == MERCADO_ABERTO: url = '{api_url}/pos-rodada/destaques'.format(api_url=self._api_url) data = self._request(url) return DestaqueRodada.from_dict(data) raise CartolaFCError('Os destaques de pós-rodada só ficam disponíveis com o mercado aberto.')
[docs] def time(self, id=None, nome=None, slug=None): """ Obtém um time específico, baseando-se no nome ou no slug utilizado. Ao menos um dos dois devem ser informado. Args: id (int): Id to time que se deseja obter. *Este argumento sempre será utilizado primeiro* nome (str): Nome do time que se deseja obter. Requerido se o slug não for informado. slug (str): Slug do time que se deseja obter. *Este argumento tem prioridade sobre o nome* Returns: Uma instância de cartolafc.Time se o time foi encontrado. Raises: cartolafc.CartolaFCError: Se algum erro aconteceu, como por exemplo: Nenhum time foi encontrado. """ if not any((id, nome, slug)): raise CartolaFCError('Você precisa informar o nome ou o slug do time que deseja obter') param = 'id' if id else 'slug' value = id if id else (slug if slug else convert_team_name_to_slug(nome)) url = '{api_url}/time/{param}/{value}'.format(api_url=self._api_url, param=param, value=value) data = self._request(url) clubes = {clube['id']: Clube.from_dict(clube) for clube in data['clubes'].values()} return data if self.json else Time.from_dict(data, clubes=clubes)
def time_parcial(self, id=None, nome=None, slug=None, parciais=None): if self.mercado().status.id == MERCADO_FECHADO: parciais = parciais if parciais else self.parciais() time = self.time(id, nome, slug) time.pontos = 0 for atleta in time.atletas: tem_parcial = atleta.id in parciais atleta.pontos = parciais[atleta.id].pontos if tem_parcial else 0 atleta.scout = parciais[atleta.id].scout if tem_parcial else {} time.pontos += atleta.pontos return time raise CartolaFCError('As pontuações parciais só ficam disponíveis com o mercado fechado.')
[docs] def times(self, query): """ Retorna o resultado da busca ao Cartola por um determinado termo de pesquisa. Args: query (str): Termo para utilizar na busca. Returns: Uma lista de instâncias de cartolafc.TimeInfo, uma para cada time contento o termo utilizado na busca. """ url = '{api_url}/times'.format(api_url=self._api_url) data = self._request(url, params=dict(q=query)) return [TimeInfo.from_dict(time_info) for time_info in data]
def _request(self, url, params=None): attempts = self.attempts while attempts: try: headers = {'X-GLB-Token': self._glb_id} if self._glb_id else None response = requests.get(url, params=params, headers=headers) if self._glb_id and response.status_code == 401: self.set_credentials(self._email, self._password) response = requests.get(url, params=params, headers={'X-GLB-Token': self._glb_id}) return parse_and_check_cartolafc(response.content.decode('utf-8')) except CartolaFCOverloadError as error: attempts -= 1 if not attempts: raise error