Want to make a Python game? Introducing PyCommands!
slickassassin03 (84)

This will be the third and last time I post this. The post I made asking if I should share this got more traction than my two release posts combined. I worked very hard on this module, and really want to see people enjoy what it is capable of. I hope you like it, please remember to upvote if you do, as it's what will gain my release some traction.

Intro

This module is called PyCommands. It is made with the intent of streamlining command line applications made by you! Its memorable syntax and limitless possibilities make it a great choice for any Python program you want to make.

I do plan on making a different post on how to do more complex things, but this is what you get for now.


Setup

  • Create a file named pycommands.py
  • Paste the below code into said file
"""
MIT License

Copyright (c) 2020 Haven Selph

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.
"""
from shlex import split


class Command:
  def __init__(self, fn, name=None, aliases=None,):
    self.name = name or fn.__name__
    self.aliases = aliases or []
    self.fn = fn

  def __call__(self, *args, **kwargs,):
    return self.fn(*args, **kwargs,)

  @property
  def all_names(self,):
    return self.name, *self.aliases


class Commands(dict):
  def __init__(self, not_found: str='{} was not recognized.', argmismatch: str='{} takes {} arguments but {} were given.',):
    self.flag = [not_found, argmismatch,]
    super().__init__()

  def _add_command(self, command,):
    for cmd_name in command.all_names:
      if cmd_name in self:
        raise ValueError(f'Name or alias assigned to function {command.fn.__name__} is duplicate: {cmd_name}',)
      self[cmd_name] = command
    
  def add_command(self, name=None, aliases=None,):
    def inner_fn(fn,):
      self._add_command(Command(fn, name, aliases,),)
      return fn
    return inner_fn

  def execute(self, user_input,):
    self.command, *args = self.parse(user_input or 'no_input',)
    if self.command.lower() in self:
      try:
        self[self.command](*args,)
      except TypeError:
        return (False, self.flag[1].format(self.command, self[self.command].fn.__code__.co_argcount, len(args,),),)
      else:
        return (True, 'Command found!',)
    else:
      return (False, self.flag[0].format(self.command,),)
  
  @staticmethod
  def parse(string,):
    if (string=='no_input'):
      return ['']*2
    try:
      return split(string,)
    except ValueError:
      return ['']*2
  • Import pycommands
  • Done!

How to use it

  • Initialize the module:
import pycommands

commands = pycommands.Commands(
 '{} was not recognized as a command',
)
  • Add Commands
@commands.add_command(name='clear','aliases=['cls',],)
def clear():
    print('\033[H\033[2J',end='',)

@commands.add_command(name='echo',)
def echo(*args,):
    print('\n'.join(args,),)
  • Create Input Loop
while True:
    cmd = commands.execute(input('>>> ',),)

    if not cmd[0]:  # Checks if command gave error
        print(cmd[1])  # Prints error message
    else:
        continue

And you are done!!! Here's what it would look like if you ran it:

>>> notacommand
notacommand was not recognized as a command
>>> echo quotes 'work in the' arguments
quotes
work in the
arguments
>>>

Wrapping Up

That's all you need to know to be able to use the module effectively, but there are many more possibilities. The more experienced of you will find them by reading the code, but for the people who need a tutorial, a post will come out soon. Please upvote this if you like it, and tell me in the comments what you plan to use it for! The program below is the program we wrote in this tutorial, I hope you enjoy, have a good time using PyCommands!

Using the Module

You are completely within your rights to release a script using this module, as long as my script contains its license header. I do ask that you credit me, but that is up to you. :)

You are viewing a single comment. View All
Jakman (168)

Ok i will use this for my viruses and rewrite it in C#. Once done with the C# version i will market it under your name if you please.

slickassassin03 (84)

@Jakman Sounds awesome, would love to have a C# version of this!

Jakman (168)

@slickassassin03 ill get back to you on that in a week or less to tell you about my progress.

slickassassin03 (84)

@Jakman Awesome man! Sorry for the slow response on my end, but I can't wait to hear back from you!

Jakman (168)

@slickassassin03 its cool. Ill use some private methods so that the user cant touch what they are not supposed to access. Ill also put in some try except conditions so that it functions like an official cmd tool. I will not fail you.

slickassassin03 (84)

@Jakman Awesome, I planned on making this more secure and did fool with extra try excepts but never got around to a stable build with them. Awesome to have you working with it!

If you have Discord it's easier to stay in touch on there:
SlickAssassin03#2003

Jakman (168)

@slickassassin03 Cool. Tell me what you want secure.

slickassassin03 (84)

@Jakman All in all, I think the whole module doesn't really need to be seen but I need to do some better documentation before that. Do you mind passing some ideas?

Jakman (168)

@slickassassin03 well first you should probably explain how this is applied in a real application

slickassassin03 (84)

@Jakman Well that's kind of in the post above. But I will work on documentation sometime soon. Need to work on other projects as of now.

I get what you're saying though. Are you able to add me on Discord?

Jakman (168)

@slickassassin03 cool. As of now i will make private what only the user cant interact with already. Just anything that would cause a error otherwise. Then i will get back to you to validate.

slickassassin03 (84)

@Jakman Ah, I think I was understanding what you meant haha. Sounds great. Primarily the upper class needs too be private, the _add_command function also should be private. Thanks for working on this though, that's really cool!

Can you reach me on discord though, that would be easier for me.

Jakman (168)

@slickassassin03 dont have it. Ill do what i can do.

slickassassin03 (84)

@Jakman Sounds good, if I don't see my repl.it for a bit my email is [email protected]

slickassassin03 (84)

@Jakman Fixed the email it was being weird, looking forward to here from you.