async def time(ctx: MtgContext, *, args: str) -> None:
    """Current time in location."""
    if len(args) == 0:
        return await ctx.send(
            '{author}: No location provided. Please type !time followed by the location you want the time for.'
            .format(author=ctx.author.mention))
    try:
        twentyfour = configuration.get_bool(
            f'{guild_or_channel_id(ctx.channel)}.use_24h'
        ) or configuration.get_bool(f'{ctx.channel.id}.use_24h')
        ts = fetcher.time(args, twentyfour)
        times_s = ''
        for t, zones in ts.items():
            cities = sorted(
                set(
                    re.sub('.*/(.*)', '\\1', zone).replace('_', ' ')
                    for zone in zones))
            times_s += '{cities}: {t}\n'.format(cities=', '.join(cities), t=t)
        await ctx.send(times_s)
    except NotConfiguredException:
        await ctx.send('The time command has not been configured.')
    except TooFewItemsException:
        logging.exception('Exception trying to get the time for %s.', args)
        await ctx.send(
            '{author}: Location not found.'.format(author=ctx.author.mention))
def in_rotation() -> bool:
    if configuration.get_bool('always_show_rotation'):
        return True
    until_full_rotation = next_rotation() - dtutil.now()
    until_supplemental_rotation = next_supplemental() - dtutil.now()
    return until_full_rotation < datetime.timedelta(
        7) or until_supplemental_rotation < datetime.timedelta(7)
 def __init__(self, interestingness: Optional[str] = None, rotation_query: Optional[str] = None, only_these: Optional[List[str]] = None) -> None:
     super().__init__()
     self.playability = card.playability()
     until_full_rotation = rotation.next_rotation() - dtutil.now()
     until_supplemental_rotation = rotation.next_supplemental() - dtutil.now()
     in_rotation = configuration.get_bool('always_show_rotation')
     if until_full_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Full rotation is in progress, ends ' + dtutil.display_date(rotation.next_rotation(), 2)
     elif until_supplemental_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Supplemental rotation is in progress, ends ' + dtutil.display_date(rotation.next_supplemental(), 2)
     elif until_full_rotation < until_supplemental_rotation:
         self.rotation_msg = 'Full rotation is ' + dtutil.display_date(rotation.next_rotation(), 2)
     else:
         self.rotation_msg = 'Supplemental rotation is ' + dtutil.display_date(rotation.next_supplemental(), 2)
     self.cards: List[Card] = []
     if in_rotation:
         self.read_rotation_files()
     self.show_interesting = True
     if interestingness:
         self.cards = [c for c in self.cards if c.get('interestingness') == interestingness]
     if only_these:
         self.cards = [c for c in self.cards if c.name in only_these]
     self.num_cards = len(self.cards)
     self.rotation_query = rotation_query or ''
Exemple #4
0
 def robots_txt(self) -> Response:
     """
     Serves the robots.txt
     """
     if configuration.get_bool('is_test_site'):
         return send_from_directory(self.static_folder, 'deny-all-robots.txt')
     return send_from_directory(self.static_folder, 'robots.txt')
Exemple #5
0
 def __init__(self, interestingness: Optional[str] = None, query: Optional[str] = '') -> None:
     super().__init__()
     until_rotation = seasons.next_rotation() - dtutil.now()
     in_rotation = configuration.get_bool('always_show_rotation')
     if until_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Rotation is in progress, ends ' + dtutil.display_date(seasons.next_rotation(), 2)
     else:
         self.rotation_msg = 'Rotation is ' + dtutil.display_date(seasons.next_rotation(), 2)
     if in_rotation:
         self.in_rotation = in_rotation
         self.show_interestingness_filter = True
         self.runs, self.runs_percent, self.cards = rotation.read_rotation_files()
         # Now add interestingness to the cards, which only decksite knows not magic.rotation.
         playability = card.playability()
         c: Card
         for c in self.cards:
             c.interestingness = rotation.interesting(playability, c)
     else:
         self.cards = []
     self.show_interesting = True
     if interestingness:
         self.cards = [c for c in self.cards if c.get('interestingness') == interestingness]
     self.num_cards = len(self.cards)
     self.query = query
     self.show_filters_toggle = True
     self.cards = [c for c in self.cards if visible(c)]
Exemple #6
0
 def __init__(self) -> None:
     super().__init__()
     until_rotation = seasons.next_rotation() - dtutil.now()
     in_rotation = configuration.get_bool('always_show_rotation')
     if until_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Rotation is in progress, ends ' + dtutil.display_date(
             seasons.next_rotation(), 2)
     else:
         self.rotation_msg = 'Rotation is ' + dtutil.display_date(
             seasons.next_rotation(), 2)
     if in_rotation:
         self.in_rotation = in_rotation
         self.runs, self.runs_percent, self.cards = rotation.read_rotation_files(
         )
     else:
         self.cards = []
     self.num_cards = len(self.cards)
def legal_cards(force: bool = False, season: str = None) -> List[str]:
    if season is None:
        url = 'legal_cards.txt'
    else:
        url = '{season}_legal_cards.txt'.format(season=season)
    encoding = 'utf-8' if season != 'EMN' else 'latin-1' # EMN was encoded weirdly.
    cached_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'legal_cards')
    if os.path.exists(os.path.join(cached_path, url)):
        h = open(os.path.join(cached_path, url), encoding=encoding)
        legal = h.readlines()
        h.close()
        return [l.strip() for l in legal]

    url = 'http://pdmtgo.com/' + url
    legal_txt = fetch_tools.fetch(url, encoding, force=force)
    if season is not None and configuration.get_bool('save_historic_legal_lists'):
        with open(os.path.join(cached_path, f'{season}_legal_cards.txt'), 'w', encoding=encoding) as h:
            h.write(legal_txt)

    return legal_txt.strip().split('\n')
Exemple #8
0
async def legal_cards_async(season: str = None) -> List[str]:
    if season is None:
        url = 'legal_cards.txt'
    else:
        url = '{season}_legal_cards.txt'.format(season=season)
    encoding = 'utf-8'
    cached_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'legal_cards')
    if os.path.exists(os.path.join(cached_path, url)):
        h = open(os.path.join(cached_path, url), encoding=encoding)
        legal = h.readlines()
        h.close()
        return [l.strip() for l in legal]

    url = 'https://pennydreadfulmtg.github.io/' + url
    legal_txt = await fetch_tools.fetch_async(url)
    if season is not None and configuration.get_bool('save_historic_legal_lists'):
        with open(os.path.join(cached_path, f'{season}_legal_cards.txt'), 'w', encoding=encoding) as h:
            h.write(legal_txt)

    return legal_txt.strip().split('\n')
Exemple #9
0
 def __init__(self, interestingness: Optional[str] = None, query: Optional[str] = '') -> None:
     super().__init__()
     until_full_rotation = rotation.next_rotation() - dtutil.now()
     until_supplemental_rotation = rotation.next_supplemental() - dtutil.now()
     in_rotation = configuration.get_bool('always_show_rotation')
     if until_full_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Full rotation is in progress, ends ' + dtutil.display_date(rotation.next_rotation(), 2)
     elif until_supplemental_rotation < datetime.timedelta(7):
         in_rotation = True
         self.rotation_msg = 'Supplemental rotation is in progress, ends ' + dtutil.display_date(rotation.next_supplemental(), 2)
     elif until_full_rotation < until_supplemental_rotation:
         self.rotation_msg = 'Full rotation is ' + dtutil.display_date(rotation.next_rotation(), 2)
     else:
         self.rotation_msg = 'Supplemental rotation is ' + dtutil.display_date(rotation.next_supplemental(), 2)
     if in_rotation:
         self.in_rotation = in_rotation
         self.show_interestingness_filter = True
         self.runs, self.runs_percent, self.cards = rotation.read_rotation_files()
         # Now add interestingness to the cards, which only decksite knows not magic.rotation.
         playability = card.playability()
         c: Card
         for c in self.cards:
             c.interestingness = rotation.interesting(playability, c)
     else:
         self.cards = []
     self.show_interesting = True
     if interestingness:
         self.cards = [c for c in self.cards if c.get('interestingness') == interestingness]
     self.num_cards = len(self.cards)
     self.query = query
     for c in self.cards:
         if c.status != 'Undecided':
             continue
         c.hits = redact(c.hits)
         c.hits_needed = redact(c.hits_needed)
         c.percent = redact(c.percent)
         c.percent_needed = redact(c.percent_needed)
     self.show_filters_toggle = True
Exemple #10
0
def create_issue(content: str,
                 author: str,
                 location: str = 'Discord',
                 repo_name: str = 'PennyDreadfulMTG/Penny-Dreadful-Tools',
                 exception: Optional[BaseException] = None) -> Issue:
    labels: List[str] = []
    issue_hash = None
    if content is None or content == '':
        return None
    body = ''
    if '\n' in content:
        title, body = content.split('\n', 1)
        body += '\n\n'
    else:
        title = content
    body += 'Reported on {location} by {author}\n\n'.format(location=location,
                                                            author=author)
    if request:
        body += '--------------------------------------------------------------------------------\n'
        body += '<details><summary><strong>Request Data</strong></summary>\n```\n'
        body += textwrap.dedent("""
            Request Method: {method}
            Path: {full_path}
            Cookies: {cookies}
            Endpoint: {endpoint}
            View Args: {view_args}
            Person: {id}
            Referrer: {referrer}
            Request Data: {safe_data}
        """.format(method=request.method,
                   full_path=request.full_path,
                   cookies=request.cookies,
                   endpoint=request.endpoint,
                   view_args=request.view_args,
                   id=session.get('id', 'logged_out'),
                   referrer=request.referrer,
                   safe_data=str(safe_data(request.form))))
        body += '\n'.join(
            ['{k}: {v}'.format(k=k, v=v) for k, v in request.headers])
        body += '\n```\n</details>\n'
        ua = request.headers.get('User-Agent', '')
        if ua == 'pennydreadfulmagic.com cache renewer':
            labels.append(ua)
        elif 'YandexBot' in ua or 'Googlebot' in ua or 'bingbot' in ua:
            labels.append('Search Engine')

    if exception:
        body += '--------------------------------------------------------------------------------\n'
        body += '<details><summary>\n'
        body += exception.__class__.__name__ + '\n'
        body += str(exception) + '\n'
        body += '</summary>\n'
        stack = traceback.extract_stack()[:-3] + traceback.extract_tb(
            exception.__traceback__)
        pretty = traceback.format_list(stack)
        body += 'Stack Trace:\n\n```Python traceback\n' + ''.join(
            pretty) + '\n```\n\n</details>\n'
        issue_hash = hashlib.sha1(''.join(pretty).encode()).hexdigest()
        body += f'Exception_hash: {issue_hash}\n'

    elif repo_name == 'PennyDreadfulMTG/perf-reports':
        stack = traceback.extract_stack()[:-3]
        pretty = traceback.format_list(stack)
        if request:
            pretty.append(request.full_path)
        issue_hash = hashlib.sha1(''.join(pretty).encode()).hexdigest()
        body += f'Location Hash: {issue_hash}\n'

    print(title + '\n' + body, file=sys.stderr)
    # Only check for github details at the last second to get log output even if github not configured.
    if not configuration.get('github_user') or not configuration.get(
            'github_password'):
        return None
    if not configuration.get_bool('create_github_issues'):
        print(f'Not creating github issue:\n{title}\n\n{body}')
        return None
    g = Github(configuration.get('github_user'),
               configuration.get('github_password'))
    git_repo = g.get_repo(repo_name)
    if repo_name == 'PennyDreadfulMTG/perf-reports':
        labels.append(location)
        if exception:
            labels.append(exception.__class__.__name__)
    if issue_hash:
        try:
            issue = g.search_issues(issue_hash, repo=repo_name)[0]
            labelstr = '; '.join(labels)
            issue.create_comment(f'{title}\n\n{body}\n\nLabels: {labelstr}')
            return issue
        except IndexError:
            pass
    issue = git_repo.create_issue(title=title, body=body, labels=labels)
    return issue
Exemple #11
0
import sys
import time
from typing import List, Optional

from generate_readme import generate_readme
from shared import configuration
from shared.pd_exception import InvalidArgumentException, TestFailedException

try:
    from plumbum import FG, local
    from plumbum.commands.processes import ProcessExecutionError
except ImportError:
    sys.stderr.write('Please run ./dev.py build\n')


ON_PROD = configuration.get_bool('production')
if ON_PROD:
    sys.stderr.write('DO NOT RUN dev.py ON PROD\n')
    sys.exit(1)

ON_WINDOWS = sys.platform == 'win32'

def run() -> None:
    try:
        try:
            exit_code = None
            run_dangerously()
        except InvalidArgumentException as e:
            exit_code = 1
            raise
        except TestFailedException as e:
def test_500() -> Response:
    if configuration.get_bool('production'):
        return return_json(generate_error(
            'ON_PROD', 'This only works on test environments'),
                           status=404)
    raise TooManyItemsException()
def in_rotation() -> bool:
    if configuration.get_bool('always_show_rotation'):
        return True
    until_rotation = seasons.next_rotation() - dtutil.now()
    return until_rotation < datetime.timedelta(7)
 def robots_txt(self):
     if configuration.get_bool('is_test_site'):
         return send_from_directory(self.static_folder,
                                    'deny-all-robots.txt')
     return send_from_directory(self.static_folder, 'robots.txt')