Creating a Class from a SplitTxn

davidcullen's Avatar

davidcullen

24 Aug, 2021 09:06 AM

Dear All,
This is another newbie question. I’m self-taught with python/jython (mainly using Google) and I’m probably overlooking something which is simple to many, but not to me.
I’m trying to create a simple python class from a SplitTxn, but I've encountered a (not obvious to me) issue.
When I print out:

print s.getParentTxn().getAccount(), type(s.getParentTxn().getAccount()).name
I get (correctly):
Real property Investments:Estuary Account
but when I create my class as:
class Split:
  def init(self, s):
    self.parent = s.getParentTxn().getAccount()
and I do within def init(self, s)::
print self.parent, type(self.parent).name
I get:
(Real property Investments:Estuary,) tuple
I would expect this output to be identical to the first output created previously.
What’s going on, and why is self.parent a tuple?

David

  1. Support Staff 1 Posted by Sean Reilly on 24 Aug, 2021 09:15 AM

    Sean Reilly's Avatar

    Hi David,

    I'm not sure why those two situations would be different either, but I don't see why the call to type() is in there at all. Can you omit that and the .name part? To get the full name of any Account object you can call .getFullAccountName().

    Thanks,
    Sean

    --
    Sean Reilly
    Developer, The Infinite Kind
    https://infinitekind.com

  2. 2 Posted by davidcullen on 24 Aug, 2021 09:23 AM

    davidcullen's Avatar

    Sean, thanks for the quick reply. Yes, I know about getFullAccountName. I used type() to get the class names (there may be a more correct way).

    Sent from my iPad

  3. 3 Posted by Stuart Beesley ... on 24 Aug, 2021 09:34 AM

    Stuart Beesley - JUST A FELLOW USER and Toolbox ‘guy’'s Avatar

    You may be bumping into the fact that when you print an object that is a class instance, then the class' internal str and repr methods get called. This is similar to repr() in Python. So on an Account object, for example, MD defines the repr as .getFullAccountName() (which includes the parent). Whereas .getAccountName() is just the name of that account.

    You don't need type().name; just type().

    NOTE: You don't seem to be setting up your class correctly. The format is:

    class MyClass:
        def __init__(self, myParameter1):
            self. myParameter1 = myParameter1
    

    (i.e. __init__)

    I suspect your tuple 'issue' is something to do with the exact format of your print command - i.e if I do something like this, I get something like you are seeing:

    a="account name"
    print (a,), type((a,))
    
    ('account name',) <type 'tuple'>
    
  4. 4 Posted by davidcullen on 24 Aug, 2021 09:55 AM

    davidcullen's Avatar

    Thanks. This makes good sense (to me) and I will explore more tomorrow.
    I didn’t explain fully before, but the **s** parameter passed to my class was actually a SplitTxn.
    Thanks for your insight.
    David

    Sent from my iPad

  5. 5 Posted by Stuart Beesley ... on 24 Aug, 2021 01:39 PM

    Stuart Beesley - JUST A FELLOW USER and Toolbox ‘guy’'s Avatar

    Ps... In Java the str and repr methods are called 'toString()'. So for the class Account it's:

    public String toString() {
        return getFullAccountName();
      }
    
  6. 6 Posted by davidcullen on 25 Aug, 2021 07:43 AM

    davidcullen's Avatar

    This may be of use to anyone following my problem.

    After much googling, by trial & error I finally solved things (there may be a simpler way, but this works for me).
    In essence, my problem was that I have a simple class which is initiated with a SplitTxn, s. The class, Split, has many variables (eg Split.amount and Split.parent, and several more) which came from SplitTxn.
    The issue I faced was that when I print either amount or parent directly, as:

    print split_txn.getValue()
    print split_txn.getParentTxn().getAccount().getAccountName().encode('utf-8')
    
    I get the correct output, as in:
    -3500000
    Estuary
    
    but when I similarly print the instance variables, as:
    print this_split.amount
    print this_split.parent
    
    I get tuples as output, such as:
    (-3500000L,)
    ('Estuary',)
    
    My “solution” was to create a specific def str(self) function (and also a special amt() functon as I wanted to format the Split.amount — I couldn’t seem to do this directly.
    Here are the relevant parts of my code for anyone interested:
    The (simplified) Class:
    class Split:
      def init(self, s):
        self.amount = s.getValue(),
        self.parent = s.getParentTxn().getAccount().getAccountName().encode('utf-8'),


    def str(self): amount = amt(self.amount) parent = '%s' % (self.parent) return "{} {}".format(amount, parent)
    and my function:
    def amt(amount):
      x = '%s' % (amount)
      return '{:,.2f}'.format(float(x)/100)
    
    I still don’t fully understand what is going on, but things are working correctly now.
    David
  7. Support Staff 7 Posted by Sean Reilly on 25 Aug, 2021 07:50 AM

    Sean Reilly's Avatar

    Hi David,

    You'll definitely want to use the currency object's formatter to get a string for any amounts. For your split I'd recommend:

    s.getAccount().getCurrencyType().format(s.geValue(), '.')

    and for the parent amount of the split (in the currency of the container/parent account, which might be different than the category's currency):

    s.getParentTxn().getAccount().getCurrencyType().format(s.getAmount(), '.')

    The integer/long value of any amount in moneydance is always specified in the smallest units of whatever currency the value is in. So while most currencies will be the amount in cents/pennies/etc there are some which will have zero or 4, or 5 decimal places.

    Thanks,
    Sean

    --
    Sean Reilly
    Developer, The Infinite Kind
    https://infinitekind.com

  8. 8 Posted by Stuart Beesley ... on 25 Aug, 2021 08:16 AM

    Stuart Beesley - JUST A FELLOW USER and Toolbox ‘guy’'s Avatar

    It is a steep learning curve and as Sean says, the .getCurrencyType() methods to convert the long values are what you need. You should not need to access the object’s instance variables at all, just use the api methods. I would also point you to .formatSemiFancy() and the other similar fancy methods.

    By no means a model of excellence, but take a look at extract_data.py from line number
    7497 where it says ‘for txn in txns:’ for an example of navigating txns, splits, and the data. Get the code from here:
    https://github.com/yogi1967/MoneydancePythonScripts/raw/master/extr...

  9. 9 Posted by davidcullen on 25 Aug, 2021 08:29 AM

    davidcullen's Avatar

    Sean/Stuart,
    Thanks both for your prompt feedback!
    I'll certainly follow things through as both you have indicated -- I still have a lot to learn!

  10. 10 Posted by davidcullen on 25 Aug, 2021 09:01 AM

    davidcullen's Avatar

    formatSemiFancy​(long amt, char decimalChar) is just what I need!

  11. 11 Posted by Stuart Beesley ... on 25 Aug, 2021 09:10 AM

    Stuart Beesley - JUST A FELLOW USER and Toolbox ‘guy’'s Avatar

    👍

  12. 12 Posted by davidcullen on 25 Aug, 2021 09:23 AM

    davidcullen's Avatar

    I’m working my way through things:
    This all works (no errors):

    acctCurr = split_txn.getParentTxn().getAccount().getCurrencyType()
    _amt = split_txn.getValue()
    
    but then when I try:
    print acctCurr.format​(_amt, ‘.')
    
    I get
    java.lang.IllegalArgumentException: Cannot create PyString with non-byte value
    
    Any ideas on what is going wrong (and how to fix things)?
  13. Support Staff 13 Posted by Sean Reilly on 25 Aug, 2021 09:36 AM

    Sean Reilly's Avatar

    It sounds like the '.' in python is a string whereas in java it is expecting a char. My understanding is that a jython string with one character should be translated to a java character, so I'm not sure why that isn't working. Maybe try a double-quoted string?

    --
    Sean Reilly
    Developer, The Infinite Kind
    https://infinitekind.com

  14. 14 Posted by Stuart Beesley ... on 25 Aug, 2021 10:07 AM

    Stuart Beesley - JUST A FELLOW USER and Toolbox ‘guy’'s Avatar

    Your quote marks are wrong. Look closely. You need plain text version of quotes.

  15. 15 Posted by davidcullen on 25 Aug, 2021 10:20 AM

    davidcullen's Avatar

    Stuart: good spotting! I’m not sure how that slipped through!

  16. 16 Posted by Stuart Beesley ... on 25 Aug, 2021 10:58 AM

    Stuart Beesley - JUST A FELLOW USER and Toolbox ‘guy’'s Avatar

    Even better. Rather than passing “.” pass this instead..:

    moneydance.getPreferences().getDecimalChar()
    
  17. 17 Posted by davidcullen on 26 Aug, 2021 04:10 AM

    davidcullen's Avatar

    I tried to follow your advice, but still no luck.
    This code:

    _amt = split_txn.getValue()
    print '_amt:  ', _amt
    dec = moneydance.getPreferences().getDecimalChar()
    print 'dec:  ', dec
    
    executes successfully (as expected), but when I try to do:
    acctCurr.format​(_amt, dec)
    
    I still get:
    Error running script: java.lang.IllegalArgumentException: Cannot create PyString with non-byte value
    
    Googling seems to indicate that this is because of a jython.2.7 known bug?
    This google find Stackover suggests that using:
    PyString str = Py.newStringOrUnicode("颜军")
    
    (modified) can solve the problem but I think this is java which I do not know well and I cannot get this to work in jython/python.

    If I cannot fix things, I’ll just use my earlier workaround.

  18. 18 Posted by Stuart Beesley ... on 26 Aug, 2021 04:23 AM

    Stuart Beesley - JUST A FELLOW USER and Toolbox ‘guy’'s Avatar

    You need this as lines 1 and 2 in your script:

    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    

    and then also, add these lines too next:

    import sys
    reload(sys)  # Dirty hack to eliminate UTF-8 coding errors
    sys.setdefaultencoding('utf8')  # Dirty hack to eliminate UTF-8 coding errors. Without this str() fails on unicode strings...
    

    I think this will eliminate a lot of your string / utf-8 errors.

  19. 19 Posted by Stuart Beesley ... on 26 Aug, 2021 04:41 AM

    Stuart Beesley - JUST A FELLOW USER and Toolbox ‘guy’'s Avatar

    PS - your code works for me OK. However, when I copy and paste your code from above, I get this see screenshot.. See the extra (hidden) square symbol! I have seen this before when copying from the moneydance api web site myself..

    What Os and Editor are you using? I have a suspicion that you are using a normal 'text editor' of some sort and not a coders editor. It's critical your file is plain text (not anything else) - like rtf.... For example on a Mac, Brackets is simple...

    ??

  20. 20 Posted by davidcullen on 26 Aug, 2021 08:40 AM

    davidcullen's Avatar

    Stuart,
    Fantastic!
    I do not know what has happened and when I look at my code, I no NOT see the square symbol in between format and (.
    However, when I fully retype the "bad" code line verbatim, it works!
    I can only think that because I used "cut & paste" for the code originally, that somehow an invisible square symbol crept into things?
    Anyway, everything seems to be working fine now.
    Thanks for your perseverance. No need to reply to the private email sent to you earlier.
    David

  21. 21 Posted by Stuart Beesley ... on 26 Aug, 2021 09:02 AM

    Stuart Beesley - JUST A FELLOW USER and Toolbox ‘guy’'s Avatar

    My recommendation to you is to switch to a (free, simple) coders tool for writing your scripts... It will stop errors to do with formatting and plain text etc.....

  22. 22 Posted by Stuart Beesley ... on 26 Aug, 2021 09:08 AM

    Stuart Beesley - JUST A FELLOW USER and Toolbox ‘guy’'s Avatar

    PS - Oddly your email didn't arrive? Can you resend? Happy to be in direct contact in the future if you like...

  23. 23 Posted by davidcullen on 27 Aug, 2021 02:07 AM

    davidcullen's Avatar

    Stuart,
    Thanks for all your help - I am learning a lot!
    Not sure why the emails did not get through - I didn't receive any delivery failure messages on my side. Anyway, things are now working so no need to trouble you further. My code is very incomplete at this stage and I'm still working on it.
    I had been using your shebangs, but not the dirty hacks which I am now using).
    I am using Nova 7.3 which I find very useful. I take your point re other editors but at this stage I will stick with it. My main errors were self-inflicted - the trailing ',' causing the tuple issue and the square which I think was caused by using "cut and paste" on the code (but works when I fully type the code).

  24. 24 Posted by Stuart Beesley ... on 27 Aug, 2021 04:58 AM

    Stuart Beesley - JUST A FELLOW USER and Toolbox ‘guy’'s Avatar

    👍

  25. 25 Posted by Stuart Beesley ... on 29 Aug, 2021 06:14 AM

    Stuart Beesley - JUST A FELLOW USER and Toolbox ‘guy’'s Avatar

    Tip. Assuming you are using sys.setdefaultencoding('utf8'), then this is a good replacement for str() where you might get utf8 issues…

    def safeStr(_theText): return ("%s" %(_theText))

  26. davidcullen closed this discussion on 26 Sep, 2021 09:57 AM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac