Regex Stuff to determinng versioning.

201 views
Skip to first unread message

Jeremy YeoKhoo

unread,
May 4, 2014, 6:47:26 AM5/4/14
to python_in...@googlegroups.com
Hey guys,

This should be fairly easy for you guys who know regex. If I have a string that I want to enable versioning, so say for an example I want to recognize a string if it contains ['v001', 'v002', etc...]
I have something like this...

remp= re.search('[0-9]+', 'hello_v001')
print temp.group()

but I dont want it to return when:
remp= re.search('[0-9]+', 'hello_001')
print temp.group()

Thanks
-Jeremy

Marcus Ottosson

unread,
May 4, 2014, 7:04:14 AM5/4/14
to python_in...@googlegroups.com
Hi Jeremy,

You can put a character in front of a pattern.
>>> re.search(r'v[0-9]+', 'hello_v001')

You can also use \d in-place of [0-9]
>>> re.search(r'v\d+', 'hello_v001')



--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/2269441f-f499-4a9a-9e08-8226214db73a%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Anthony Tan

unread,
May 4, 2014, 7:07:11 AM5/4/14
to Jeremy YeoKhoo, python_in...@googlegroups.com

If the leading 'v' is the relevant thing, would '_[Vv][0-9]+' do?

(Its just hunting for an underscore, lowercase OR uppercase v, then a string of numbers)

Justin Israel

unread,
May 4, 2014, 7:18:47 AM5/4/14
to python_in...@googlegroups.com, Jeremy YeoKhoo

The re module also has a case insensitive flag:

re.search(r'_v\d+', 'hello_v001', re.I)

You can also limit it to a 3 padded version scheme if you want to go that far:

re.search(r'_v\d{3}', 'hello_v001', re.I)

Eduardo Grana

unread,
May 4, 2014, 12:16:14 PM5/4/14
to python_in...@googlegroups.com, Jeremy YeoKhoo
Hello Jeremy,
One thing i found very usefull is the groups method of re.match,
so you can get parts of the matched pattern
for example,

>>> import re
>>> st = 'hello_v001' 
>>> regex = '(.*)_[vV]([0-9]{3})$' # notice the ( ) to separate the parts you get later, the $ represents the end of the string, the .* will match anything
>>> re.match(regex, st)
<_sre.SRE_Match object at 0x01DC53C8>
>>> r = re.match(regex, st)
>>> r.groups()
('hello', '001')

Cheers!
Eduardo





For more options, visit https://groups.google.com/d/optout.



--
Eduardo Graña
www.eduardograna.com.ar

Marcus Ottosson

unread,
May 4, 2014, 12:41:22 PM5/4/14
to python_in...@googlegroups.com, Jeremy YeoKhoo
Very useful! Always wondered why that command was called "group" when I only ever got a single result back. :)



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Jeremy YeoKhoo

unread,
May 4, 2014, 7:05:42 PM5/4/14
to python_in...@googlegroups.com
Thanks for that everyone,

Didnt know the padded version < ie [\d(3)] >
nor the $ to search end the string.


Cool stuff!!

Eduardo Grana

unread,
May 5, 2014, 12:01:41 PM5/5/14
to python_in...@googlegroups.com, Jeremy YeoKhoo
Hello!
You can also get a dictionary out of the matched groups...

import re

name = 'hello_v001.ma'

regex = '^(?P<name>.*)_[vV](?P<version>[0-9]{3})\.(?P<extension>.*)$'

# notice the ?P<version> inside of the () groups

match = re.match(regex, name)

match.groupdict()

# Result: {'version': '001', 'name': 'hello', 'extension': 'ma'} #


Although the expression gets a little bit more obscure

Cheers!

Eduardo 




For more options, visit https://groups.google.com/d/optout.



--
Eduardo Graña
www.eduardograna.com.ar

Jeremy YeoKhoo

unread,
May 5, 2014, 7:47:45 PM5/5/14
to python_in...@googlegroups.com
Hey Eduardo!

That's definitely very useful. Regex is obviously used for some serious syntax-organising by software developers and those tidbits of information would invariably be useful for what we do in in CG. I see potential in using it in this context whereby, say for an example.

<sequence>_<shot>_<version>_<minorversion>.<fileExtension>

Great to know that there is a built-in function as groups() and groupdict() now


On Sunday, 4 May 2014 20:47:26 UTC+10, Jeremy YeoKhoo wrote:

Chad Dombrova

unread,
May 5, 2014, 10:14:15 PM5/5/14
to python_in...@googlegroups.com, python_in...@googlegroups.com
Regular expressions are an incredibly powerful tool, and an understanding of them is a requirement for any aspiring TD.  

That said, 2 things they lack are readability and composability.  If you are designing a parsing system for naming conventions from scratch I recommend having a look at pyparsing: https://pypi.python.org/pypi/pyparsing/2.0.2

Its object-oriented approach means that you can build up common path patterns that can be reused to form complex but readable compositions.  This will make it easier to adapt as your your naming convention grows in complexity over time, and you want to add new directories and name tokens to tell the difference between an export, a stereo render, a working scene file, etc. 

Chad. 

Sent from Mailbox


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Jeremy YeoKhoo

unread,
May 6, 2014, 7:12:13 PM5/6/14
to python_in...@googlegroups.com
Thanks so much Chad, yes I agree. Not many TDs are aware or understand the necessity of good program design and structure (me included!) and in this case naming convention! Ill have to have a look at that and apply what I can to my own set of tools that i am currently in the process of creating

Thanks
-Jeremy


On Sunday, 4 May 2014 20:47:26 UTC+10, Jeremy YeoKhoo wrote:

Marcus Ottosson

unread,
May 7, 2014, 1:42:31 AM5/7/14
to python_in...@googlegroups.com
Just reading up on Pyparsing so I could be off here, but I would actually argue that if a codebase relies heavily enough on strings (for identification?) that regex no longer cuts it, I would consider whether or not there is a better way of doing it, and not necessarily turn to heavier guns in parsing.

Again, I could very well be misunderstanding. Does anyone have an example of Pyparsing in action?


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Stefan Andersson

unread,
May 7, 2014, 2:34:34 AM5/7/14
to python_in...@googlegroups.com
So here is a though. How would you guys go about to sort versioning that has no padding? For instance Nuke always adds v1,v2,v3 etc without padding. And some users are used to do that when versioning their files. I try and trap most of those things to add padding. But... there is always that case when you can't. 


how would you sort and print the last version? In a clever way. Right now there is a lot of splitting and sorting for me to get it right. But it feels there would be a "smart" way with regex, but I can't get my head around how to use that.

regards
stefan








For more options, visit https://groups.google.com/d/optout.



--
Stefan Andersson | Digital Janitor
social media -> "sanders3d"

Marcus Ottosson

unread,
May 7, 2014, 2:51:59 AM5/7/14
to python_in...@googlegroups.com

You could do something like this:

>>> version = re.search(r'v\d+.nk', 'my_nukeFile_v12.nk').group()
>>> version
'v12.nk'

At this point, you are guaranteed to always have a ‘v’ infront, and that it will always end with ‘.nk’. At which point you could

>>> version = int(version[1:-3])
12



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
May 7, 2014, 3:06:38 AM5/7/14
to python_in...@googlegroups.com

Sorry, I completely missed the part of your questions containing the example. :)

# 1. Get all string in a dict together with their version number
pattern = re.compile(r'\d+')
versions = {}
for test in v:
    version = pattern.search(test).group()
    version = int(version)
    versions[version] = test

# 2. Sort version numbers and fill up a new list of strings
sorted_versions = []
for version in sorted(versions):
    sorted_versions.append(versions[version])

print sorted_versions

['test_v1.ma', 'test_v2.ma' ...]
--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
May 7, 2014, 4:35:42 AM5/7/14
to python_in...@googlegroups.com
If you know you are always parsing strings that have some form of a "v<version>" and you are just worried about padding, then you can use a very targeted regex to produce a numeric sort key:

import re
sorted(v, key=lambda s: int(re.findall(r'_v(\d+)\.', s)[-1]))

This is just finding the "_v<number>" pattern, and converting that to an int to use for sorting.

But if you wanted a more general solution, where you wanted to sort a generic string, but doing numeric sorting where possible, you could do something like this:

def string_to_key(s):
    return [(int(i) if i.isdigit() else i) for i in re.split(r'(\d+)', s)]

sorted(v, key=string_to_key)

The string_to_key() function just takes a string like "test_1_and_2_and_then_34_finally_v1.ma" and produces a list where the numbers are actual ints:

# ['test_', 1, '_and_', 2, '_and_then_', 34, '_finally_v', 1, '.ma']

Then you use that as a key function in the call to sort and it will make sure to do numeric comparisons. I actually use something like this in Qt for sort filter proxy where I need the column to be sorted, taking into account trailing numbers that aren't padded.

I think the point of using pyparsing is that regular expressions, while powerful, can be complicated when they get to be large patterns and try to take into account many rules. They are hard to debug because essentially they are just big pattern strings. Pyparsing is defining a grammer. I haven't used it, but I can see where it would be useful when you have many rules that need to be considered.



Stefan Andersson

unread,
May 7, 2014, 4:35:46 AM5/7/14
to python_in...@googlegroups.com
Thanks! Though I can't get my head around those
re.compile(r'\d+')




For more options, visit https://groups.google.com/d/optout.

Justin Israel

unread,
May 7, 2014, 4:38:01 AM5/7/14
to python_in...@googlegroups.com
The re.compile() thing is a small optimization where you compile the pattern ahead of time so that it doesn't have to do it each time you reuse it. The re module actually caches the last 100 patterns anyways, so it only really matters if you have many regular expressions that you are using over and over again. 


Stefan Andersson

unread,
May 7, 2014, 4:40:51 AM5/7/14
to python_in...@googlegroups.com
Thanks guys!
Lot's of information there!

regards
stefan




For more options, visit https://groups.google.com/d/optout.

Marcus Ottosson

unread,
May 7, 2014, 5:13:56 AM5/7/14
to python_in...@googlegroups.com
Pyparsing is defining a grammer. I haven't used it, but I can see where it would be useful when you have many rules that need to be considered.

Ah, see, this is where I hesitate. If you've got that many rules to begin with, doesn't that mean you've quite reliant on strings for things that may be better suited for composition of objects, or a pre-defined schema for lists and the like?

I'm eager to witness an example.



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
May 7, 2014, 7:02:47 AM5/7/14
to python_in...@googlegroups.com
But what if strings are exactly the thing you have to be dealing with? Consider you are trying to design a way to parse paths in a VFX-style pipeline. You define a naming convention that will be followed, which could have different path strings depending on the specific context. Maybe something like:

/projects/<project>/<scene>       /<shot>  /<type/stage>/<resolution_colorspace>/<version>/<file.ext>
/projects/<project>/<asset.type>/<name>/<type/stage>/<resolution_colorspace|representation>/<version>/<file.ext>

And maybe even the /project prefix is optional.

I feel like what you might be suggesting in terms of objects, composition, lists, ... ultimately is the same thing that pyparsing would be trying to abstract for you. From what I have read in the docs, what you are getting with pyparsing is grammar primitives, such as a "Word". A Word in this case might be the format that defines asset.type. And then you take all of these primatives combine them, in a reusable way, into the representation of different paths. 

So if I defined words/regex for:

  • project
  • scene
  • asset
  • shot
  • assetName
  • type
  • resolution
  • colorspace
  • version
  • ...
Then I can start combing those. Like taking a definition for resolution and colorspace and saying <resolution>_<colorspace>, or being able to reuse the definition for a project format across different path types. Or being able to say the '/project' prefix is optional in terms of parsing the path. 

I too would like to see some examples from someone who has pyparsing experience. But this is what I gleaned from looking over the wiki and docs.  Reusable definitions at the word level, to be combined/composed into larger grammars that can be used to parse strings. After all...paths are strings. Either you are going to define big regular expressions to break down the variations of these paths, or you are going to hand roll a class that has a bunch of branching code to split and parse the components, or you are going to use a library like pyparsing to define grammar and let it handle the parsing for you. 




Marcus Ottosson

unread,
May 7, 2014, 8:05:26 AM5/7/14
to python_in...@googlegroups.com

That’s a good point; paths could potentially be filled with rules that need to be broken down, re-defined often and remain well understood.

I would however argue whether or not it is a good idea to rely this heavily on paths in the first place, as it seems better suited for a schema.

About object composition and schemas, this is what I’m picturing as an alternative to (my understanding of) pyparsing:

Objects

>>> project.shot(1000).used_assets()
['myasset1', 'myasset2']

As opposed to

>>> path = '/projects/hulk/1000/used_assets/myasset1'
>>> project, shot, assets = parse(path)

Schema

As an alternative, a schema might be defined as:

['root', 'project', 'shot' ,'used_asset]

Which would map each level of a hierarchy to the respective index.

# For example
$ /myprojects/hulk/1000/myasset1
$       0      1    2     3



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
May 7, 2014, 3:38:00 PM5/7/14
to python_in...@googlegroups.com

Marcus that is exactly what you do with pyparsing. 

If it helps to call it a schema then let's call it that. The list you made with the 4 string elements is that same as if you defined 4 word rules in pyparsing and the list itself is the same as the mechanism they give you to combine them into a grammar. This grammar can then be used to parse the path string. The only difference I see between what you are showing and what pyparsing seems to offer is that pyparsing would be more robust in defining the rules.  For instance,  you have just assigned indexes to a paths split components. But what if index 4 is different depending on what 3 evaluates to. What if 4 can be broken up into two individual components like res_colorspace? That is the stuff you could define as part of the grammar.

Also there isn't anything saying you couldn't wrap the parsing into something that gives you object oriented access like a Project object. But at some point,  you will have a path and you will need to parse it to be able to generate the instances of your objects. Starting with the name of a project would be straightforward if you then wanted to access a shot off it by name.

Marcus Ottosson

unread,
May 7, 2014, 3:59:38 PM5/7/14
to python_in...@googlegroups.com
To be clear, schemas and parsing are not one and the same.


It really isn't a matter of splitting hairs.

This is an example of schemas in action.

And the re module, and possibly pyparsing, is an example of parsing.




For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
May 7, 2014, 5:45:48 PM5/7/14
to python_in...@googlegroups.com
Thank you for sharing the definition of a database schema with me. I would not have know this otherwise.
I'm not going to further the debate since I think it's not going anywhere productive.  


Marcus Ottosson

unread,
May 7, 2014, 6:08:54 PM5/7/14
to python_in...@googlegroups.com
Justin, I'm sorry you felt that the wikipedia links were directed at you, the definitions were meant for this conversation and its readers as some may or may not be aware of them. I  honestly can't read anyone's mind or know what they already know, but you did seem to imply that they were both one and the same just now and I just wanted to point out that they may in fact be different.


On Wednesday, May 7, 2014, Justin Israel <justin...@gmail.com> wrote:
Thank you for sharing the definition of a database schema with me. I would not have know this otherwise.
I'm not going to further the debate since I think it's not going anywhere productive.  
On Thu, May 8, 2014 at 7:59 AM, Marcus Ottosson <konstr...@gmail.com> wrote:
To be clear, schemas and parsing are not one and the same.


It really isn't a matter of splitting hairs.

This is an example of schemas in action.

And the re module, and possibly pyparsing, is an example of parsing.



On 7 May 2014 20:38, Justin Israel <justin...@gmail.com> wrote:

Marcus that is exactly what you do with pyparsing. 

If it helps to call it a schema then let's call it that. The list you made with the 4 string elements is that same as if you defined 4 word rules in pyparsing and the list itself is the same as the mechanism they give you to combine them into a grammar. This grammar can then be used to parse the path string. The only difference I see between what you are showing and what pyparsing seems to offer is that pyparsing would be more robust in defining the rules.  For instance,  you have just assigned indexes to a paths split components. But what if index 4 is different depending on what 3 evaluates to. What if 4 can be broken up into two individual components like res_colorspace? That is the stuff you could define as part of the grammar.

Also there isn't anything saying you couldn't wrap the parsing into something that gives you object oriented access like a Project object. But at some point,  you will have a path and you will need to parse it to be able to generate the instances of your objects. Starting with the name of a project would be straightforward if you then wanted to access a shot off it by name.

On May 8, 2014 12:05 AM, "Marcus Ottosson" <konstr...@gmail.com> wrote:

That’s a good point; paths could potentially be filled with rules that need to be broken down, re-defined often and remain well understood.

I would however argue whether or not it is a good idea to rely this heavily on paths in the first place, as it seems better suited for a schema.

About object composition and schemas, this is what I’m picturing as an alternative to (my understanding of) pyparsing:

Objects

>>> project.shot(1000).used_assets()
['myasset1', 'myasset2']

As opposed to


For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAPGFgA0tuGQPb1gexKupGDgf74dp_6sB%2Br7oGqn4X7P%3DNqNjEw%40mail.gmail.com.

For more options, visit https://groups.google.com/d/optout.


--
Marcus Ottosson
konstr...@gmail.com


Risto Jankkila

unread,
May 8, 2014, 3:10:04 AM5/8/14
to python_in...@googlegroups.com
Below is a good thread about using regex to do a similar thing. I found the answer by Shane Holloway especially interesting.


Cheers,
Risto




For more options, visit https://groups.google.com/d/optout.



--
-------------------------------------------
Risto Jankkila
mob. +44 (0)77 6741 9890 (UK)
mob. +358 (0)40 5422 625 (FI)
ristoj...@gmail.com
-------------------------------------------

Justin Israel

unread,
May 8, 2014, 3:32:38 AM5/8/14
to python_in...@googlegroups.com

Nice link.

Since its on topic in case anyone is interested,  my coworker wrote a library for parsing sequences and managing complex ranges,  called fileseq

https://github.com/sqlboy/fileseq

Pretty useful stuff that is common at studios

Risto Jankkila

unread,
May 8, 2014, 3:48:25 AM5/8/14
to python_in...@googlegroups.com
That fileseq lib is a lifesaver! 

Makes me almost sorry that I'm not setting up an ad hoc digital intermediate pipeline at the moment. Thanks!

/Risto



For more options, visit https://groups.google.com/d/optout.

Matt Estela

unread,
May 8, 2014, 3:55:38 AM5/8/14
to python_in...@googlegroups.com

Marcus Ottosson

unread,
May 8, 2014, 4:02:14 AM5/8/14
to python_in...@googlegroups.com

Fredrik Averpil

unread,
May 8, 2014, 4:05:17 AM5/8/14
to python_in...@googlegroups.com
Regarding regex and such ... as long as you use scripts with predefine naming conventions, you can rely on the same regex always working. That's what we do here. In short, artists never get to name their files.

This causes file structures to get basically unreadable as every scene or script file is generated by a script, but this is remedied by a project manager inside of Nuke/Maya (PySide) which translates these file's names into something more useful (based on a JSON containing a nicer and more descriptive name). This also makes it possible to rename files and folders whenever you like. It could cause some headache when rerouting Maya references, but apart from that - not so much issues.

We don't use this for all software, though. Only for software which supports python and pyside. Works better than you'd think.


Regards,
Fredrik


Marcus Ottosson

unread,
May 15, 2014, 3:06:45 PM5/15/14
to python_in...@googlegroups.com
About regex, this book has helped me both initially and on numerous occasions and also gave me some perspective on some of the potential of regular expressions.


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Andres Weber

unread,
May 16, 2014, 10:40:01 AM5/16/14
to python_in...@googlegroups.com
Always plugging amazing books Marcus...I'm going to go broke buying all your suggestions ;).  Just bought this!


On Thursday, May 15, 2014 3:06:45 PM UTC-4, Marcus Ottosson wrote:
About regex, this book has helped me both initially and on numerous occasions and also gave me some perspective on some of the potential of regular expressions.
On 8 May 2014 09:05, Fredrik Averpil <fredrik...@gmail.com> wrote:
Regarding regex and such ... as long as you use scripts with predefine naming conventions, you can rely on the same regex always working. That's what we do here. In short, artists never get to name their files.

This causes file structures to get basically unreadable as every scene or script file is generated by a script, but this is remedied by a project manager inside of Nuke/Maya (PySide) which translates these file's names into something more useful (based on a JSON containing a nicer and more descriptive name). This also makes it possible to rename files and folders whenever you like. It could cause some headache when rerouting Maya references, but apart from that - not so much issues.

We don't use this for all software, though. Only for software which supports python and pyside. Works better than you'd think.


Regards,
Fredrik


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.



--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
May 16, 2014, 10:55:57 AM5/16/14
to python_in...@googlegroups.com
Haha, sryy and glad you like 'em :)
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/6367fc36-8880-4951-8e0e-6cab1dbcaa47%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.


--
Marcus Ottosson
konstr...@gmail.com


Anthony Tan

unread,
May 16, 2014, 11:23:16 AM5/16/14
to python_in...@googlegroups.com
If you're not wedded to having hardcopies, perhaps consider a safari subscription?

Depends on your usage profile but I find I tend to grab chapters here and there - my sub lets me do that more effectively than when I was buying books.

Marcus Ottosson

unread,
May 16, 2014, 11:32:52 AM5/16/14
to python_in...@googlegroups.com
Personally I'm going for kindle whenever I can. If there is one thing I don't like about kindle however its the formatting. Does safari maintain the layout and formatting from the respective books, Anthony?


On Friday, May 16, 2014, Anthony Tan <antho...@greenworm.net> wrote:
If you're not wedded to having hardcopies, perhaps consider a safari subscription?

Depends on your usage profile but I find I tend to grab chapters here and there - my sub lets me do that more effectively than when I was buying books.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/201405161523.s4GFNL8O031581%40atl4mhob08.myregisteredsite.com.

For more options, visit https://groups.google.com/d/optout.


--
Marcus Ottosson
konstr...@gmail.com


Anthony Tan

unread,
May 16, 2014, 7:54:09 PM5/16/14
to python_in...@googlegroups.com

I think so, but its been a while since I had a physical copy to compare against.

Jeremy YeoKhoo

unread,
May 17, 2014, 2:03:27 AM5/17/14
to python_in...@googlegroups.com
Ummm I actually googled that book and added a pdf suffix to it. Hypothetically, it would have been nice to download it.

Personally, since Ive started freelancing, having these books electronically works for me, though I would prefer a hard copy myself.

Marcus Ottosson

unread,
May 17, 2014, 8:07:46 AM5/17/14
to python_in...@googlegroups.com

I think so, but its been a while since I had a physical copy to compare against.

Cool, thanks for letting me know, I’ll check it out.



--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Reply all
Reply to author
Forward
0 new messages