Search code examples
pythonargparse

Python use same argument several times keep as string


I'm new to python and trying to figure out how to make this code accept multiple of the same argument -ex. I tried make it a action='append' but that gives me a error saying it need to be a string not a list. right now when using -ex several times it just uses the last instance of it example. python3 scrunch.py --no-rep -ex 123 -ex 456 5 5 abcdefg123456 output 12345 the output still contains 123.

import string
import argparse
import itertools
from math import factorial



def number_permutations(n, k):
 return factorial(n)/factorial(n-k)

def main():
    parser = argparse.ArgumentParser(description='Generate password combinations from charset'
    'with length in range: [MIN..MAX]. '
    'If any of -u, -l, -d, -hex option is set, then charset is ignored, but still must be provided.')

    parser = argparse.ArgumentParser(epilog="Example 1: "
    'python3 scrunch.py --no-rep -ex ABC 3 5 ABCDEFGH123456 '
    'Example 2: '
    'python3 scrunch.py --no-rep -f wordlist.txt -u -l -d 6 6 DUMMYCHARSET')

    parser.add_argument('-f', metavar='file', help='output text file name. Prints to STDOUT by default')
    parser.add_argument('-u', action='store_true', help='Use all uppercase characters. Overrides charset')
    parser.add_argument('-l', action='store_true', help='Use all lowercase characters. Overrides charset')
    parser.add_argument('-d', action='store_true', help='Use all decimal numbers. Overrides charset')
    parser.add_argument('-hex', action='store_true', help='Use all hex numbers. Overrides charset')
    parser.add_argument('-ex', help='Exclude char sequence')
    parser.add_argument('--no-digit-start', action='store_true', help='Do not start with digit')
    parser.add_argument('minlen', metavar='MIN', type=int,
                        help='Min length of combination')
    parser.add_argument('maxlen', metavar='MAX', type=int,
                        help='Max length of combination')
    parser.add_argument('charset', nargs=1)
    parser.add_argument('--no-rep', action='store_true', help='Any symbol can occur only once.')

    args = parser.parse_args()
    print (args.ex)
    a = ''.join(args.charset)
    b = ''
    if args.u:
     b += string.ascii_uppercase
    if args.l:
     b += string.ascii_lowercase
    if args.hex:
     b += string.hexdigits
    if args.d:
     b += string.digits

    if b:
      a = b

    s = sorted(a)
    print ("Sorted charset: {}".format(s))
    num = 0
    # Calculate number of possible combinations
    for L in range(args.minlen, args.maxlen + 1):
     num += number_permutations(len(s), L)
    print ("Number of permutations: %d" % num)

    if args.f:
     f = open(args.f, 'w')

    for L in range(args.minlen, args.maxlen + 1):
     if args.no_digit_start and args.no_rep:
      gen = permutations_no_digit_start(s, L)
     elif args.no_rep:
      gen = itertools.permutations(s, L)
     else:
      gen  = itertools.product(s, repeat=L)
     for x in gen:
      y = ''.join(x)
      if args.ex and args.ex in y:
       continue
      if args.no_digit_start and y[0].isdigit():
       continue
      if args.f:
       f.write("%s\n" % ''.join(x))
      else:
       print (''.join(x))

main()

Solution

    1. replace line

      parser.add_argument('-ex', help='Exclude char sequence')
      

      to

      parser.add_argument('-ex', action='append', help='Exclude char sequence')
      
    2. replace if check

      if args.ex and args.ex in y:
        continue
      

      to

      bad_pattern = False
      for ex in args.ex:
        if ex and ex in y:
          bad_pattern = True
          break
      if bad_pattern:
        continue
      

    Explanation: by default only last value of -ex used. And that is 456. But action='append' allows to set list of values. And every usage of -ex will append new value to list. After that you have to check every value in args.ex list by iterating for ex in args.ex