Recent Changes

Tuesday, August 29

  1. msg Odd .copy() behaviour message posted Odd .copy() behaviour Haven't forgotten you - I looked back through history to see what the impetus was for this change, …
    Odd .copy() behaviour
    Haven't forgotten you - I looked back through history to see what the impetus was for this change, but did not see the specific bug or case that inspired it. I did make your change and reran my unit tests, and all appears to be okay, but I still want to revisit my history dive.

    Thanks for your patience,
    -- Paul
    5:07 am

Sunday, August 27

  1. msg += operator and user function for math equation message posted += operator and user function for math equation I am new to parsing and have just come accross this tool which looks great. For my work, I need …
    += operator and user function for math equation
    I am new to parsing and have just come accross this tool which looks great.

    For my work, I need to parse multiple lines of math equations with variables and user defined functions inside. For example, with 3 lines of string:
    x = 1
    y = Max(1,2)
    x += y
    I want to be able to get x = 3 and y = 2 at the end.

    Below is my attempt on this. I am just trying to make a slight modification to the fourFn.py and SimpleCalc.py examples in the wiki page.
    import operator
    from pyparsing import Literal,Word,Combine,Optional,ZeroOrMore,Forward,nums,\
        alphas
    from collections import defaultdict
     
    def main():
        global exprStack
        exprStack = []
        global varStack
        varStack  = []
        global variables
        variables = defaultdict(float)
        l = ['x=1','y=abs(2)', 'x+=y']
        for item in l:
            source = item
            L = BNF().parseString( source )
            print(L)
            result = evaluateStack( exprStack[:] )
            print(varStack)
            print(result)
            variables[varStack.pop()]=result
            print(variables)
     
    def Scalar(x):
        return x
     
    def pushFirst( strg, loc, toks ):
        exprStack.append( toks[0] )
     
    def assignVar( strg, loc, toks ):
        varStack.append( toks[0] )
     
    bnf = None
    def BNF():
        """
        expop   :: '^'
        multop  :: '*' | '/'
        addop   :: '+' | '-'
        integer :: ['+' | '-'] '0'..'9'+
        atom    :: real | fn '(' expr ')' | '(' expr ')'
        factor  :: atom [ expop factor ]*
        term    :: factor [ multop factor ]*
        expr    :: term [ addop term ]*
        iaddop  :: '+='
        assign  :: '='
        """
        global bnf
        if not bnf:
            point = Literal( "." )
            fnumber = Combine( Word( "+-"+nums, nums ) + 
                               Optional( point + Optional( Word( nums ) ) ))
            ident = Word(alphas+"_", alphas+nums+"_")
     
            plus  = Literal( "+" )
            minus = Literal( "-" )
            mult  = Literal( "*" )
            div   = Literal( "/" )
            lpar  = Literal( "(" ).suppress()
            rpar  = Literal( ")" ).suppress()
            addop  = plus | minus
            multop = mult | div
            expop = Literal( "^" )
            assign = Literal( "=" )
            iaddop = Literal("+=")
     
            expr = Forward()
            atom = ( fnumber | ident + lpar + expr + rpar | ident ).setParseAction(pushFirst) | ( lpar + expr.suppress() + rpar )
     
            # by defining exponentiation as "atom [ ^ factor ]..." instead of "atom [ ^ atom ]...", we get right-to-left exponents, instead of left-to-righ
            # that is, 2^3^2 = 2^(3^2), not (2^3)^2.
            factor = Forward()
            factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( pushFirst ) )
     
            term = factor + ZeroOrMore( ( multop + factor ).setParseAction( pushFirst ) )
            expr << term + ZeroOrMore( ( addop + term ).setParseAction( pushFirst ) )
            bnf =  ident.setParseAction(assignVar) + (assign | iaddop.setParseAction( pushFirst )) + expr
        return bnf
     
    # map operator symbols to corresponding arithmetic operations
    opn = { "+" : operator.add,
            "-" : operator.sub,
            "*" : operator.mul,
            "/" : operator.truediv,
            "^" : operator.pow,
            "+=" : operator.iadd}
    fn  = { "Max" : max,
            "Min" : min,
            "abs" : abs,
           "Scalar" : Scalar}
     
    def evaluateStack( s ):
        op = s.pop() 
        if op in "+-*/^" or op in '+=':
            op2 = evaluateStack( s )
            op1 = evaluateStack( s )
            return opn[op]( op1, op2 )
        elif op in fn:
            return fn[op]( evaluateStack( s ) )
        elif op in variables:
            return variables[op]        
        else:
            return float( op )
     
    if __name__ == '__main__':
        main()

    But I have faced two issues.
    1. The += operator is not working as expected. With input string as ['x=1','y=2', 'x+=y'], I still get x= 1 in the end. <-- defaultdict(<class 'float'>, {'x': 1.0, 'y': 2.0})
    2. My user defined funciton name will have the same name convention as the variable name convention. The only difference is that the function will have parentheses followed. I tried to modify the atom definition but it is not working as expected. With input string as ['x=1','y=abs(2)', 'x+=y'], I got a ValueError: could not convert string to float: 'y'.

    Would you help to shred some lights on how to fix the problem? Thanks.
    7:25 pm

Monday, August 21

  1. user_add ckot71 ckot71 joined pyparsing
    6:36 am

Friday, August 18

  1. msg schemaSQL.parseFile(f) fails if parseAll=True attemted message posted schemaSQL.parseFile(f) fails if parseAll=True attemted Thanks for your help again!!! Haven't yet mastered virtualenv (I installed virtualenvwrapper-win …
    schemaSQL.parseFile(f) fails if parseAll=True attemted
    Thanks for your help again!!!
    Haven't yet mastered virtualenv (I installed virtualenvwrapper-win on windows), but tracked down and deleted all the pyparsing.pyc-s windows could find, and checked the version in every pyparsing.py source windows could find.
    To my great embarrassment the ONLY 1.4.11 was the one I downloaded from somewhere during internet search and put it right next to my source in the eclipse workspace.
    The others ranged from 2.0.1.10 - 2.2.0 (I recently installed with pip).
    After clearing that and restarting eclips the version is 2.2.0 (Yayyyy!)
    No if only I could fix the tcl/tk so mathplotlip could work :)
    10:42 am

Thursday, August 17

  1. msg Odd .copy() behaviour message posted Odd .copy() behaviour My first thought is that this is actually a bug in copy(). I'll look at this in more detail this we…
    Odd .copy() behaviour
    My first thought is that this is actually a bug in copy(). I'll look at this in more detail this weekend. I'll also take a look at what you have described and see if there is a reasonable workaround or alternative.
    9:28 pm
  2. msg schemaSQL.parseFile(f) fails if parseAll=True attemted message posted schemaSQL.parseFile(f) fails if parseAll=True attemted I've started sorting out these kinds of packaging issues using virtualenv, which allows you a lot m…
    schemaSQL.parseFile(f) fails if parseAll=True attemted
    I've started sorting out these kinds of packaging issues using virtualenv, which allows you a lot more flexibility to try installing/removing packages without messing up your system environment. If you are absolutely desperate, pyparsing's code is just a single .py file, so you can extract that and put it explicitly in your PYTHONPATH wherever you choose - but do this only as a last resort, or as a temporary workaround until you get your overall packaging bits resolved.
    9:20 pm
  3. msg Odd .copy() behaviour message posted Odd .copy() behaviour Ok – with a bit of poking around I understodd how this behaviour comes about: the copy() does a dee…
    Odd .copy() behaviour
    Ok – with a bit of poking around I understodd how this behaviour comes about: the copy() does a deep copy or the dependent expressions. The .addParseAction in enable_tree then hits a "dead", unused ParserElement.

    Now, I'd really love to be able to attach actions after the fact. I'd still like to use .setResultsName (which does an implicit copy). I *think* what I want is shallow copies of self.exprs; current pyparsing does an explicit copy since 1.5.3 (or somesuch) around line 3324:

            ret.exprs = [e.copy() for e in self.exprs]

    Does anyone remember what would break if I restored the previous behaviour, which, I think, essentially is equivalent to

            ret.exprs = self.exprs[:]

    (depending on copy.copy() semantics, I guess).
    5:10 am

Wednesday, August 16

  1. msg Odd .copy() behaviour message posted Odd .copy() behaviour I've finally made the jump from 1.5.2 or so to 2.1.10, and what kept me from upgrading back then b…
    Odd .copy() behaviour
    I've finally made the jump from 1.5.2 or so to 2.1.10, and what kept me
    from upgrading back then bites me again: .copy() changes the behaviour
    of ParserElements since 1.5.2:

    Here's an example:

    import pprint
    from pyparsing import Word, ZeroOrMore, alphas
     
    def get_grammar():
        vanishing = Word(alphas)
        item = "foo" | vanishing
        item_seq = item + ZeroOrMore( item )
        return locals()
     
    def enable_tree(syms):
        for name, ob in syms.iteritems():
            ob.setParseAction(lambda s, p, t, name=name: (name,)+tuple(t))
     
    if __name__=="__main__":
        g = get_grammar()
        enable_tree(g)
        pprint.pprint(g["item_seq"].parseString("foo bar")[0])

    If you ignore the plumbing, it's a trivial sequence grammar. The stuff
    is arranged to spit out a representation of the parse tree, and if you
    try it, you'll see it's printing the expected

    ('item_seq', ('item', 'foo'), ('item', ('vanishing', 'bar')))

    However, if you now change the grammar to:

    def get_grammar():
        vanishing = Word(alphas)
        item = "foo" | vanishing
        item = item.copy()       # <--- inserting a call to copy
        item_seq = item + ZeroOrMore( item )
        return locals()

    pyparsing doesn't "see" the "vanishing" nonterminal any more, and the
    output is:

    ('item_seq', ('item', 'foo'), ('item', 'bar'))

    In more complex grammars, you'll see that only the level below the
    copied (or, more dramatically, setResultsName-d) element is swallowed --
    rules deeper down are again correctly represented.

    Is this expected behaviour? I'm asking because apparently no one got
    hit by this in the past eight years apart from me, so somehow I suspect
    I'm being stupid. Am I?
    8:12 am

Monday, August 14

  1. msg schemaSQL.parseFile(f) fails if parseAll=True attemted message posted schemaSQL.parseFile(f) fails if parseAll=True attemted Sorry for the n00b question, but how can I rectify this? C:\Python27\Lib\site-packages\pyparsing…
    schemaSQL.parseFile(f) fails if parseAll=True attemted
    Sorry for the n00b question, but how can I rectify this?

    C:\Python27\Lib\site-packages\pyparsing.py has
    def parseFile( self, file_or_filename, parseAll=False ):

    And the C:\Python27\Lib\site-packages\pyparsing-2.2.0-py2.7.egg-info folder has some text files, but didn't find traces of the earlier version.
    Any "tools of the trade" advice?
    Would uninstalling the whole python and installing -say- activepython distro would help?
    7:46 am

Sunday, August 13

  1. msg schemaSQL.parseFile(f) fails if parseAll=True attemted message posted schemaSQL.parseFile(f) fails if parseAll=True attemted 1.4.11 Thank you, you are right as always :)
    schemaSQL.parseFile(f) fails if parseAll=True attemted
    1.4.11
    Thank you, you are right as always :)
    8:14 pm

More