0

The program I am working does the following:

  • Grabs stdout from a .perl program
  • Builds a nested dict from the output

I'm using the AutoVivification approach found here to build a default nested dictionary. I'm using this method of defaultdict because it's easier for me to follow as a new programmer.

I'd like to add one key value to a declared key per pass of the for line in the below code. Is there a easier way to add values to a key beyond making a [list] of values then adding said values as a group?

import pprint

class Vividict(dict):
    def __missing__(self, key):
        value = self[key] = type(self)()
        return value

reg = 'NtUser'
od = Vividict()
od[reg]

def run_rip():
    os.chdir('/Users/ME/PycharmProjects/RegRipper2.8')  # Path to regripper dir
    for k in ntDict:
        run_command = "".join(["./rip.pl", " -r 
                              /Users/ME/Desktop/Reg/NTUSER.DAT -p ", str(k)])  
        process = subprocess.Popen(run_command,
                               shell=True,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
        out, err = process.communicate()  # wait for the process to terminate
        parse(out)
        # errcode = process.returncode // used in future for errorcode checking
        ntDict.popitem(last=False)

def parse(data):
    pattern = re.compile('lastwrite|(\d{2}:\d{2}:\d{2})|alert|trust|Value')
    grouping = re.compile('(?P<first>.+?)(\n)(?P<second>.+?)
                         ([\n]{2})(?P<rest>.+[\n])', re.MULTILINE | re.DOTALL)
    if pattern.findall(data):
        match = re.search(grouping, data)
        global first
        first = re.sub("\s\s+", " ", match.group('first'))
        od[reg][first]
        second = re.sub("\s\s+", " ", match.group('second'))
        parse_sec(second)

def parse_sec(data):
    pattern = re.compile(r'^(\(.*?\)) (.*)$')
    date = re.compile(r'(.*?\s)(.*\d{2}:\d{2}:\d{2}.*)$')
    try:
        if pattern.match(data):
            result = pattern.match(data)
            hive = result.group(1)
            od[reg][first]['Hive'] = hive
            desc = result.group(2)
            od[reg][first]['Description'] = desc

        elif date.match(data):
            result = date.match(data)
            hive = result.group(1)
            od[reg][first]['Hive'] = hive
            time = result.group(2)
            od[reg][first]['Timestamp'] = time

        else:
            od[reg][first]['Finding'] = data

    except IndexError:
         print('error w/pattern match')

run_rip()
pprint.pprint(od)

Sample Input:

bitbucket_user v.20091020
(NTUSER.DAT) TEST - Get user BitBucket values

Software\Microsoft\Windows\CurrentVersion\Explorer\BitBucket
LastWrite Time Sat Nov 28 03:06:35 2015 (UTC)

Software\Microsoft\Windows\CurrentVersion\Explorer\BitBucket\Volume
LastWrite Time = Sat Nov 28 16:00:16 2015 (UTC)
Community
  • 1
  • 1
ImNotLeet
  • 351
  • 3
  • 18
  • @Jonrsharpe I noticed you edited/removed my add-on question, since there is no way to message directly can you elaborate on why you thought it was not relevant? – ImNotLeet Feb 29 '16 at 23:30
  • ...because your add-on question *was irrelevant*, it's simply not on-topic. That kind of meta-content is not appropriate for questions on SO - if you want to discuss things like that, see http://meta.stackoverflow.com/. – jonrsharpe Feb 29 '16 at 23:31
  • @jonrsharpe I don't know if your a mod, or someone with just a high score count. But as you can tell by my flair I'm new. Since I'm engaging you I would hope it's obvious I want to improve my ability to accurately depict a SO problem and it is frustrating as a user to be immediately down-voted on topics that are considered remedial to the more experienced user-base. Is there a better meta to ask these kind of "beginner" questions? – ImNotLeet Feb 29 '16 at 23:35
  • I'm afraid I have no idea what you're asking in this question. It seems like you're asking about something in loop, but it's all abstracted away by your `#do stuff` comment. Can you more clearly explain what you're doing and what you want to do differently? – Blckknght Feb 29 '16 at 23:37
  • @Blckknght formatted for readability, please let me know if it helps? I'm trying to learn how SE works and contribute questions that make sense. – ImNotLeet Feb 29 '16 at 23:46
  • 1
    It's still not actually valid syntactically, please give a [mcve]. – jonrsharpe Feb 29 '16 at 23:50
  • I still don't understand what you're asking for. What `[list]` are you talking about? That's not anywhere in your code. What do you mean by "build dict per pass"? How does that differ from what you're doing now? – Blckknght Feb 29 '16 at 23:54
  • @Blckknght the current interaction is a tuple and I'm unsure how to interact with the dict in a way that will allow me to add additional values beyond the most recent. Since the dict is being declared on the fly is there a temp variable I should call to do a append? – ImNotLeet Mar 01 '16 at 00:03
  • @jonrsharpe read your link, I hope the above is more in-line with the expectations set forth in that guide. – ImNotLeet Mar 01 '16 at 00:09
  • Not really, it doesn't say what output you expected and what you got instead and isn't exactly minimal – jonrsharpe Mar 01 '16 at 00:10
  • @jonrsharpe so how would I present the dependancies in the script in a minimalist way? Is there another way to ask how to add more than one value to a key? – ImNotLeet Mar 01 '16 at 00:15

1 Answers1

1

If I understand your question correctly, you want to change the lines where you're actually adding values to your dictionary (e.g. the od[reg][first]['Hive'] = hive line and the similar one for desc and time) to create a list for each reg and first value and then extend that list with each item being added. Your dictionary subclass takes care of creating the nested dictionaries for you, but it won't build a list at the end.

I think the best way to do this is to use the setdefault method on the inner dictionary:

od[reg][first].setdefault("Hive", []).append(hive)

The setdefault will add the second value (the "default", here an empty list) to the dictionary if the first argument doesn't exist as a key. It preempts the dictionary's __missing__ method creating the item, which is good, since we want a the value to be list rather than another layer of dictionary. The method returns the value for the key in all cases (whether it added a new value or if there was one already), so we can chain it with append to add our new hive value to the list.

Blckknght
  • 85,872
  • 10
  • 104
  • 150