0

I'm currently working in an eLearning platform, and I'm trying to add some PEP8 validation to the assignment solutions students are submitting to the system in order to give then some extra feedback about how good or bad the solution they proposed is.

I found that using the python pep8 package it's not that simple to check PEP8 errors just in a chunk of code (in my case, it would be the posted solution to the assignment), without specifying any path to a specific file in the filesystem.

Is it actually possible or the pep8 library doesn't allow it? Of course I could save the posted solution in a tmp file and run the validation from there, but I would like to avoid this extra step.

Did anyone have the same issue?

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Martin Zugnoni
  • 1,439
  • 2
  • 14
  • 21
  • Sorry for contradicting your word, but IMO this not a duplication of `How do I wrap a string in a file in Python?`. The fact that both solutions use `StringIO` doesn't mean that both questions are the same. The problematic here was fully related to the `pep8` module. There was even an answer written by @Hugh Bothwell that doesn't involve `StringIO` at all. Sorry @TigerhawkT3 but I think this is not a duplicated question (actually I've checked before writing it). – Martin Zugnoni Dec 07 '15 at 11:09

2 Answers2

1

I finally found the way to validate PEP8 errors using an in-memory file

import pep8
import StringIO

code_to_be_checked = """
import random
import string


class SimplePasswordGenerator(object):

    list_of_chars = [string.letters, string.digits, string.punctuation]
    union_of_chars = list(set().union(*list_of_chars))

    def __init__(self, available_chars=union_of_chars, length=8):
        self.available_chars = available_chars
        self.length = length

    def __iter__(self):
        return self

    def next(self):  # use __next__ in Python 3.x
        password = ''.join([random.choice(self.available_chars) for i in range(self.length)])
        return password
"""

myfile = StringIO.StringIO(code_to_be_checked)
fchecker = pep8.Checker(lines=myfile.readlines(), show_source=True)
errors = fchecker.check_all()

print("PEP8 error count: {}".format(errors))

NOTE: If your are using Python 3.x, you will need to use io.StringIO instead.

Martin Zugnoni
  • 1,439
  • 2
  • 14
  • 21
  • 1
    When you say you 'finally' found a way, you seem to have answered your own question in the same minute you asked it!? Anyway, you can check online; http://pep8online.com/ – markwalker_ Dec 05 '15 at 21:26
  • @marksweb, There is nothing wrong with answering OP's own question. For details, you can see it http://stackoverflow.com/help/self-answer – Ahsanul Haque Dec 05 '15 at 21:33
  • 1
    What's the `pep8` module? It doesn't seem to be in the standard library. – TigerhawkT3 Dec 05 '15 at 21:33
  • @AhsanulHaque I didn't suggest there was a problem. Just that when I ask a question, if I have my own solution at the time, I'd make it a part of my question. – markwalker_ Dec 05 '15 at 21:37
  • Frankly using `StringIO` to do this is fairly obvious, IMHO. – martineau Dec 05 '15 at 21:39
  • Actually, you can store your thoughts on a question answer pair, even if you know the answer from the start. Some people do this so that they can refer people to this question while answering related questions. – Ahsanul Haque Dec 05 '15 at 21:41
  • It looks like this module requires a `list` of strings. Why did you need to wrap it in a `StringIO` object first? – TigerhawkT3 Dec 05 '15 at 21:42
0

It looks like it can be done without StringIO; just use str.splitlines, like so:

import pep8

code_to_be_checked = """
import random
import string


class SimplePasswordGenerator(object):

    list_of_chars = [string.letters, string.digits, string.punctuation]
    union_of_chars = list(set().union(*list_of_chars))

    def __init__(self, available_chars=union_of_chars, length=8):
        self.available_chars = available_chars
        self.length = length

    def __iter__(self):
        return self

    def next(self):  # use __next__ in Python 3.x
        password = ''.join([random.choice(self.available_chars) for i in range(self.length)])
        return password
"""

fchecker = pep8.Checker(lines=code_to_be_checked.splitlines(True), show_source=True)
errors = fchecker.check_all()

print("PEP8 error count: {}".format(errors))

The only trick is that the input lines need to end in newlines; str.splitlines(keepends=True) does that.

Edit: after further checking, it looks like the problem is simpler - the first line cannot be length==0 or it causes an error in UTF-8 checking. Your test code just happens to start with an empty line ;-)

Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99