Full Code of architv/chcli for AI

master e9e387b9a85c cached
11 files
14.8 KB
4.1k tokens
17 symbols
1 requests
Download .txt
Repository: architv/chcli
Branch: master
Commit: e9e387b9a85c
Files: 11
Total size: 14.8 KB

Directory structure:
gitextract_jrlqgli4/

├── .gitignore
├── LICENSE
├── README.md
├── challenges/
│   ├── __init__.py
│   ├── cli.py
│   ├── local_exceptions.py
│   ├── platformids.py
│   ├── utilities.py
│   └── writers.py
├── requirements.txt
└── setup.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.pyc
challenges/*.pyc

config.py
README
README.txt

# Distribution / packaging
.Python
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# Installer logs
pip-log.txt
pip-delete-this-directory.txt



================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2015 Archit Verma

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README.md
================================================
Challenge CLI
=====

[![PyPI version](https://badge.fury.io/py/challenge-cli.svg)](https://badge.fury.io/py/challenge-cli)

Programming Challenges for Hackers - a CLI for all the programming challenges. 

![](http://i.imgur.com/F7BbEH2.png)

Install
=====

### Using `pip`

```bash
$ pip install challenge-cli
````

### Build from source


```bash
$ git clone git@github.com:architv/chcli.git
$ cd chcli
$ python setup.py install
```

Usage
====

### Get active challenges

```bash
$ challenges --active
$ challenges --active -p HR -p TC # get active challenges from HackerRank(HR) and topcoder(TC).
```

### Get upcoming challenges

```bash
$ challenges --upcoming
```

### Open a challenge in browser

```bash
$ challenges --active 1 # opens the first active challenge in your browser
```

### Get upcoming challenges from a particular platform

```bash
$ challenges --upcoming -p HR -p TC # HR and TC are platform code for HackerRank and TopCoder Respectively
```

### Get short challenges

```bash
$ challenges --short -p CF # get all the short challenges from codeforces
```

### Get hiring challenges

```bash
$ challenges --hiring # get all the hiring challenges
```

### Get challenges from all platforms with a set time period

```bash
$ challenges -t 2 # get all the active challenges and upcoming challenges which start in the next 2 days
```

### Help
```bash
$ challenges --help
```

### Platform and Platform codes

- TC: topcoder.com
- HR: hackerrank.com
- CF: codeforces.com
- HE: hackerearth.com
- CC: codechef.com
- GCJ: Google Code Jam
- KA: kaggle.com

For a full list of supported platform and platform codes [see this](challenges/platformids.py).

Demo
====

### Active Challenges
![](http://i.imgur.com/Siedm4R.gif)

### Open a challenge in browser
![](http://i.imgur.com/mxsrc8C.gif)

### Hiring Challenges
![](http://i.imgur.com/c30BEqG.gif)

### Short Challenges from a particular list of platform
![](http://i.imgur.com/SKQgona.png?1)

### Upcoming Challenges within 1 day
![](http://i.imgur.com/3mX7YGh.png)

Todo
====
- [ ] Fix alignment issues


Licence
====
Open sourced under [MIT License](LICENSE)

Support
====
If you like my work, please support the project by donating.

- https://gratipay.com/~architv


================================================
FILE: challenges/__init__.py
================================================


================================================
FILE: challenges/cli.py
================================================
import sys
import webbrowser

import requests
import click

from local_exceptions import IncorrectParametersException

import writers

from platformids import platforms as contest_platforms
from utilities import time_difference

BASE_URL = "http://challengehuntapp.appspot.com/v2"
PLATFORM_IDS = contest_platforms

def check_platforms(platforms):
  """Checks if the platforms have a valid platform code"""
  if len(platforms) > 0:
    return all(platform in PLATFORM_IDS for platform in platforms)
  return True


def get_contests_data():
  """Gets all the data for all the contests"""
  req = requests.get(BASE_URL)

  if req.status_code == requests.codes.ok:
    return req.json()
  else:
    click.secho("Couldn't get the data", fg="red", bold=True)
    click.secho("Exiting...", fg="red", bold=True)
    sys.exit()

def get_platform_filter(platforms):
    if platforms:
        platform_filter = [PLATFORM_IDS[platform] for platform in platforms]
    else:
        platform_filter = PLATFORM_IDS.values()
    return platform_filter

def active_contests(platforms):
  """Gets all the active contests based on time and platforms"""
  contests_data = get_contests_data()
  platform_filter = get_platform_filter(platforms)

  active_challenges = [contest for contest in contests_data["active"] if contest["host_name"] in platform_filter]

  return active_challenges
  

def upcoming_contests(platforms, time):
  """Gets all the upcoming contests based on time and platforms"""
  contests_data = get_contests_data()
  platform_filter = get_platform_filter(platforms)

  upcoming_challenges = [contest for contest in contests_data["pending"] if contest["host_name"] in platform_filter 
    and time_difference(contest["start"]).days <= time]

  return upcoming_challenges


def hiring_contests():
  """Gets all the hiring challenges from all the availbale platforms"""
  contests_data = get_contests_data()
  active_contests = contests_data["active"]
  upcoming_contests = contests_data["pending"]
  get_challenge_name = lambda x : x.lower().split()
  hiring_challenges = [contest for contest in active_contests
    if "hiring" in get_challenge_name(contest["contest_name"])]
  hiring_challenges += [contest for contest in upcoming_contests
    if "hiring" in get_challenge_name(contest["contest_name"])]
  return hiring_challenges


def short_contests(platforms):
  """Gets all the short contests(less than or equal to 4 hours of duration)"""
  contests_data = get_contests_data()
  active_contests = contests_data["active"]
  upcoming_contests = contests_data["pending"]

  platform_filter = get_platform_filter(platforms)
  get_challenge_duration = lambda x : int(x.split(":")[0]) if "days" not in x else float("inf")
  short_contests = [contest for contest in active_contests
    if get_challenge_duration(contest["duration"]) <= 4 and contest["host_name"] in platform_filter]
  short_contests += [contest for contest in upcoming_contests
    if get_challenge_duration(contest["duration"]) <= 4 and contest["host_name"] in platform_filter]
  return short_contests


def get_all_contests(platforms, time):
  """Gets all the contests and writes it to standard output"""
  contests_data = get_contests_data()
  active_contests = contests_data["active"]
  upcoming_contests = contests_data["pending"]

  platform_filter = get_platform_filter(platforms)

  contests_data = [contest for contest in active_contests 
  if contest["host_name"] in platform_filter]
  contests_data += [contest for contest in upcoming_contests 
  if contest["host_name"] in platform_filter and time_difference(contest["start"]).days <= time]
  return contests_data


@click.command()
@click.option('--active', is_flag=True, help="Shows all the active contests")
@click.option('--upcoming', is_flag=True, help="Shows all the upcoming contests")
@click.option('--hiring', is_flag=True, help="Shows all the hiring contests")
@click.option('--short', is_flag=True, help="Shows all the short contests")
@click.option('--platforms', '-p', multiple=True,
              help=("Choose the platform whose contests you want to see. "
                    "See platform codes for more info"))
@click.argument('goto', nargs=1, required=False, type=click.INT)
@click.option('--time', '-t', default=6,
              help="The number of days in the past for which you want to see the contests")
def main(active, upcoming, hiring, short, goto, platforms, time):
  """A CLI for active and upcoming programming challenges from various platforms"""

  if not check_platforms(platforms):
    raise IncorrectParametersException('Invlaid code for platform. Please check the platform ids')

  try:
    if active:
      active_challenges = active_contests(platforms)
      if goto:
        webbrowser.open(active_challenges[goto - 1]["contest_url"], new=2)
      else:
        writers.write_contests(active_challenges, "active")
      return

    if upcoming:
      upcoming_challenges = upcoming_contests(platforms, time)
      if goto:
        goto = int(goto)
        webbrowser.open(upcoming_challenges[goto - 1]["contest_url"], new=2)
      else:
        writers.write_contests(upcoming_challenges, "upcoming")
      return

    if hiring:
      hiring_challenges = hiring_contests()
      if goto:
        webbrowser.open(hiring_challenges[goto - 1]["contest_url"], new=2)
      else:
        writers.write_contests(hiring_challenges, "hiring")
      return

    if short:
      short_challenges = short_contests(platforms)
      if goto:
        goto = int(goto)
        webbrowser.open(short_challenges[goto - 1]["contest_url"], new=2)
      else:
        writers.write_contests(short_challenges, "short")
      return

    all_contests = get_all_contests(platforms, time)
    if goto:
      webbrowser.open(all_contests[goto - 1]["contest_url"], new=2)
    else:
      writers.write_contests(all_contests, "all")
  except IncorrectParametersException as e:
    click.secho(e.message, fg="red", bold=True)

if __name__ == '__main__':
  main()


================================================
FILE: challenges/local_exceptions.py
================================================
class IncorrectParametersException(Exception):
  pass

================================================
FILE: challenges/platformids.py
================================================
platforms = {
	"UA": "usaco.org",
  "CC": "codechef.com", 
  "EOL":"e-olimp.com",
  "CH24": "ch24.org", 
  "HR": "hackerrank.com", 
  "HE": "hackerearth.com",
  "ICPC": "icfpcontest.org", 
  "GCJ": "google.com/codejam", 
  "DE24": "deadline24.pl", 
  "IOI": "stats.ioinformatics.org", 
  "PE": "projecteuler.net", 
  "SN": "contests.snarknews.info", 
  "CG": "codingame.com", 
  "CF": "codeforces.com", 
  "ELY": "e-olymp.com",
  "DMOJ": "dmoj.ca",
  "MARA": "marathon24.com",
  "IPSC": "ipsc.ksp.sk", 
  "UVA": "uva.onlinejudge.org",
  "OPEN": "opener.itransition.com", 
  "HSIN": "hsin.hr/coci",
  "CFT": "ctftime.org", 
  "KA": "kaggle.com",
  "TC": "topcoder.com",
  "FBHC": "facebook.com/hackercup"
}

================================================
FILE: challenges/utilities.py
================================================
from datetime import datetime, timedelta
from time import strptime

from collections import namedtuple

def format_date(date_object):
  """Formats the date and returns the datetime object"""
  # date_time = date_object.split("+")
  return datetime.strptime(str(date_object), "%Y-%m-%dT%H:%M:%S")


def time_difference(target_time):
  """Calculate the difference between the current time and the given time"""
  TimeDiff = namedtuple("TimeDiff", ["days", "hours", "minutes", "seconds"])
  time_diff = format_date(target_time) - datetime.utcnow()
  hours, remainder = divmod(time_diff.seconds, 3600)
  minutes, seconds = divmod(remainder, 60)
  return TimeDiff(days=time_diff.days, hours=hours, minutes=minutes, seconds=seconds)


================================================
FILE: challenges/writers.py
================================================
import json

import click

from utilities import time_difference

def colors():
  """Creates an enum for colors"""
  enums = dict(
    TIME_LEFT="red",
    CONTEST_NAME="yellow",
    HOST="green",
    MISC="blue",
    TIME_TO_START="green",
  )

  return type('Enum', (), enums)


def challenge():
  """Creates an enum for contest type"""
  enums = dict(
    ACTIVE="active",
    UPCOMING="upcoming",
    HIRING="hiring",
    ALL="all",
    SHORT="short",
  )

  return type('Enum', (), enums)


def write_contests(contests, contest_type):
  """Prints the contests based on the parameters passed"""
  write_contest_header(contest_type)

  for index, contest in enumerate(contests):

    time_diff_string = get_time_string(contest, contest_type)
    contest_name = contest["contest_name"].encode('utf-8')

    click.echo()
    click.secho("%-3s" % str(index+1), nl=False, bold=True)
    click.secho("  %-50s" %
                contest_name, nl=False, fg=colors().CONTEST_NAME, bold=True)
    click.secho("    %-20s" % time_diff_string, nl=False, fg=colors().TIME_TO_START, bold=True)
    click.secho("    %-11s" %
                 str(contest["duration"]), nl=False, bold=True)
    click.secho("    %-15s" % contest["host_name"], fg=colors().HOST, bold=True)


def get_time_string(contest, contest_type):
  """Return a string with time for the contest to begin/end"""

  if contest_type == challenge().ACTIVE:
    time_diff = time_difference(contest["end"])
  elif contest_type == challenge().UPCOMING:
    time_diff = time_difference(contest["start"])
  elif contest_type in [challenge().HIRING, challenge().SHORT, challenge().ALL]:
    try:
      time_diff = time_difference(contest["start"])
    except:
      time_diff = time_difference(contest["end"])
  time_diff_string = ""

  if time_diff.days > 0: 
    time_diff_string = "{0} days {1} hours".format(time_diff.days, time_diff.hours)
  elif time_diff.hours > 0:
    time_diff_string = "{0} hours {1} minutes".format(time_diff.hours, time_diff.minutes)
  else:
    time_diff_string = "{0} minutes".format(time_diff.minutes)
  return time_diff_string


def write_contest_header(contest_type):
  """Prints the header for the type of contest"""
  if contest_type == challenge().ACTIVE:
    click.secho("%-3s  %-50s    %-20s    %-11s    %-15s" % 
    ("NO.", "NAME", "ENDS IN", "DURATION", "PLATFORM"))
  elif contest_type == challenge().UPCOMING:
    click.secho("%-3s  %-50s    %-20s    %-11s    %-15s" % 
    ("NO.", "NAME", "STARTS IN", "DURATION", "PLATFORM"))
  elif contest_type in [challenge().HIRING, challenge().SHORT, challenge().ALL]:
    click.secho("%-3s  %-50s    %-20s    %-11s    %-15s" % 
    ("NO.", "NAME", "STARTS/ENDS IN", "DURATION", "PLATFORM"))    


================================================
FILE: requirements.txt
================================================
argparse==1.2.1
click==5.1
requests==2.7.0
wsgiref==0.1.2


================================================
FILE: setup.py
================================================
#!/usr/bin/env python

from setuptools import setup
import sys

setup(
    name='challenge-cli',
    version='0.0.1.0',
    description='Programming challenges for hackers',
    author='Archit Verma',
    license='MIT',
    classifiers=[
        # How mature is this project? Common values are
        #   3 - Alpha
        #   4 - Beta
        #   5 - Production/Stablegit
        'Development Status :: 3 - Alpha',
        'Intended Audience :: Developers',
        'Topic :: Software Development :: Build Tools',
        'License :: OSI Approved :: MIT License',

        # Specify the Python versions you support here. In particular, ensure
        # that you indicate whether you support Python 2, Python 3 or both.
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.6',
        'Programming Language :: Python :: 2.7',
    ],
    keywords = "programming challenges competitive topcoder codeforces tool cli",
    author_email='architv07@gmail.com',
    url='https://github.com/architv/chcli',
    packages=['challenges'],
    install_requires=[
        "click>=5.0",
        "requests==2.7.0"
    ] + (["colorama==0.3.3"] if "win" in sys.platform else []),
    entry_points = {
        'console_scripts': [
            'challenges = challenges.cli:main'
      ],
    }
)
Download .txt
gitextract_jrlqgli4/

├── .gitignore
├── LICENSE
├── README.md
├── challenges/
│   ├── __init__.py
│   ├── cli.py
│   ├── local_exceptions.py
│   ├── platformids.py
│   ├── utilities.py
│   └── writers.py
├── requirements.txt
└── setup.py
Download .txt
SYMBOL INDEX (17 symbols across 4 files)

FILE: challenges/cli.py
  function check_platforms (line 17) | def check_platforms(platforms):
  function get_contests_data (line 24) | def get_contests_data():
  function get_platform_filter (line 35) | def get_platform_filter(platforms):
  function active_contests (line 42) | def active_contests(platforms):
  function upcoming_contests (line 52) | def upcoming_contests(platforms, time):
  function hiring_contests (line 63) | def hiring_contests():
  function short_contests (line 76) | def short_contests(platforms):
  function get_all_contests (line 91) | def get_all_contests(platforms, time):
  function main (line 117) | def main(active, upcoming, hiring, short, goto, platforms, time):

FILE: challenges/local_exceptions.py
  class IncorrectParametersException (line 1) | class IncorrectParametersException(Exception):

FILE: challenges/utilities.py
  function format_date (line 6) | def format_date(date_object):
  function time_difference (line 12) | def time_difference(target_time):

FILE: challenges/writers.py
  function colors (line 7) | def colors():
  function challenge (line 20) | def challenge():
  function write_contests (line 33) | def write_contests(contests, contest_type):
  function get_time_string (line 52) | def get_time_string(contest, contest_type):
  function write_contest_header (line 75) | def write_contest_header(contest_type):
Condensed preview — 11 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (17K chars).
[
  {
    "path": ".gitignore",
    "chars": 256,
    "preview": "*.pyc\nchallenges/*.pyc\n\nconfig.py\nREADME\nREADME.txt\n\n# Distribution / packaging\n.Python\nenv/\nbin/\nbuild/\ndevelop-eggs/\nd"
  },
  {
    "path": "LICENSE",
    "chars": 1078,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Archit Verma\n\nPermission is hereby granted, free of charge, to any person obta"
  },
  {
    "path": "README.md",
    "chars": 2239,
    "preview": "Challenge CLI\n=====\n\n[![PyPI version](https://badge.fury.io/py/challenge-cli.svg)](https://badge.fury.io/py/challenge-cl"
  },
  {
    "path": "challenges/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "challenges/cli.py",
    "chars": 5999,
    "preview": "import sys\nimport webbrowser\n\nimport requests\nimport click\n\nfrom local_exceptions import IncorrectParametersException\n\ni"
  },
  {
    "path": "challenges/local_exceptions.py",
    "chars": 53,
    "preview": "class IncorrectParametersException(Exception):\n  pass"
  },
  {
    "path": "challenges/platformids.py",
    "chars": 705,
    "preview": "platforms = {\n\t\"UA\": \"usaco.org\",\n  \"CC\": \"codechef.com\", \n  \"EOL\":\"e-olimp.com\",\n  \"CH24\": \"ch24.org\", \n  \"HR\": \"hacker"
  },
  {
    "path": "challenges/utilities.py",
    "chars": 727,
    "preview": "from datetime import datetime, timedelta\nfrom time import strptime\n\nfrom collections import namedtuple\n\ndef format_date("
  },
  {
    "path": "challenges/writers.py",
    "chars": 2726,
    "preview": "import json\n\nimport click\n\nfrom utilities import time_difference\n\ndef colors():\n  \"\"\"Creates an enum for colors\"\"\"\n  enu"
  },
  {
    "path": "requirements.txt",
    "chars": 58,
    "preview": "argparse==1.2.1\nclick==5.1\nrequests==2.7.0\nwsgiref==0.1.2\n"
  },
  {
    "path": "setup.py",
    "chars": 1317,
    "preview": "#!/usr/bin/env python\n\nfrom setuptools import setup\nimport sys\n\nsetup(\n    name='challenge-cli',\n    version='0.0.1.0',\n"
  }
]

About this extraction

This page contains the full source code of the architv/chcli GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 11 files (14.8 KB), approximately 4.1k tokens, and a symbol index with 17 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!