tag:blogger.com,1999:blog-4620065251949857262024-03-26T05:02:30.045-04:00Sandro TosiA blog about things I do: Debian, Linux, Python, whateverSandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.comBlogger35125tag:blogger.com,1999:blog-462006525194985726.post-21700556305449106192021-05-10T17:07:00.003-04:002021-05-10T17:07:40.462-04:00Empire State Building Lights iCalendar<p>I'm very lucky to be able to see the Empire State Building from my apartment windows, and at night the lights are fantastic! But i'm also curious to know what's going to be today's lights, and tomorrow, etc.</p><p>I thought I'd easily find a calendar to add to gCal to show that, but i wasn't able to find any, so I made it myself: <a href="https://sandrotosi.github.io/esb-lights-calendar/">https://sandrotosi.github.io/esb-lights-calendar/</a></p>Sandro Tosihttp://www.blogger.com/profile/13017373086527472437noreply@blogger.com0tag:blogger.com,1999:blog-462006525194985726.post-56949115053021635932020-12-08T02:13:00.009-05:002021-11-04T09:45:13.848-04:00Python: send emails with embedded images<p>to send emails with images you need to use <span style="font-family: courier;">MIMEMultipart</span>, but the basic approach:</p>
<pre><code class="python">import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
msg = MIMEMultipart('alternative')
msg['Subject'] = "subject"
msg['From'] = from_addr
msg['To'] = to_addr
part = MIMEImage(open('/path/to/image', 'rb').read())
s = smtplib.SMTP('localhost')
s.sendmail(from_addr, to_addr, msg.as_string())
s.quit()
</code>
</pre>
<p>will produce an email with empty body and the image as an attachment.</p><p>The better way, ie to have the image as part of the body of the email, requires to write an HTML body that <i>refers</i> to that image:</p>
<pre><code class="python">import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
msg = MIMEMultipart('alternative')
msg['Subject'] = "subject
msg['From'] = from_addr
msg['To'] = to_addr
text = MIMEText('<img src="cid:image1">', 'html')
msg.attach(text)
image = MIMEImage(open('/path/to/image', 'rb').read())
# Define the image's ID as referenced in the HTML body above
image.add_header('Content-ID', '<image1>')
msg.attach(image)
s = smtplib.SMTP('localhost')
s.sendmail(from_addr, to_addr, msg.as_string())
s.quit()
</code>
</pre>
The trick is to define an image with a specific Content-ID and make that the only item in an HTML body: now you have an email with contains that specific image as the only content of the body, embedded in it.<div><br /></div><div><b>Bonus point</b>: if you want to take a snapshot of a webpage (which is kinda the reason i needed the code above) i found it extremely useful to use the <a href="https://developers.google.com/speed/docs/insights/v5/get-started" target="_blank">Google PageSpeed Insights API</a>; a good description on how to use that API with Python is available at <a href="https://stackoverflow.com/a/63929634/1929629">this</a> StackOverflow answer.</div><div><br /></div><div><b>UPDATE</b> (2020-12-26): I was made aware via email that some mail providers may not display images inline when the <span style="font-family: courier;">Content-ID</span> value is too short (say, for example, <span style="font-family: courier;">Content-ID: 1</span>). A solution that seems to work on most of the providers is using a sequence of random chars prefixed with a dot and suffixed with a valid mail domain.</div>Sandro Tosihttp://www.blogger.com/profile/13017373086527472437noreply@blogger.com0tag:blogger.com,1999:blog-462006525194985726.post-69803735193664714792020-05-08T22:37:00.001-04:002020-05-08T23:08:26.463-04:00It's a waiting game... but just how long we gotta wait?While waiting for my priority date to become current, and with enough "quarantine time" on my hand, i just come up with a very simple Python tool to parse the <a href="https://travel.state.gov/content/travel/en/legal/visa-law0/visa-bulletin.html" target="_blank">USCIS Visa Bulletin</a> to gather some data from that.<br />
<br />
You can find code and images in this <a href="https://github.com/sandrotosi/uscis-visa-bulletin" target="_blank">GitHub repo</a>.<br />
<br />
For now it only contains a single plot for the EB3 final action date; it answers a simple question: how many months ago your priority date should be if you want to file your AOS on that month. We started from FY2016, to cover the final full year of the Obama administration.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-6NSndbpdClI/XrYWsc_mnlI/AAAAAAAA-as/89DQpYQTOQUvPmznHEWoXS8O9iCvZ0XBwCLcBGAsYHQ/s1600/EB3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="960" data-original-width="1536" height="400" src="https://1.bp.blogspot.com/-6NSndbpdClI/XrYWsc_mnlI/AAAAAAAA-as/89DQpYQTOQUvPmznHEWoXS8O9iCvZ0XBwCLcBGAsYHQ/s640/EB3.png" width="640" /></a></div>
If you're interested in more classes/visas, let me know and the tool could be easily extended to cover that too. PRs are always welcome.Sandro Tosihttp://www.blogger.com/profile/13017373086527472437noreply@blogger.com0tag:blogger.com,1999:blog-462006525194985726.post-6619809372045033592012-11-21T12:29:00.000-05:002012-11-21T13:44:59.737-05:00Attending the CodecademyYou've probably already got it, I'm surveying several sites to improve programming skills. This episode is about <a href="http://www.codecademy.com/">Codecademy</a>.<br />
<br />
It's a very well done site, for people that want to <i>learn</i> a language. It has a <a href="http://www.codecademy.com/tracks/python">Python track</a>, along with several others: Ruby, JQuery, Javascript & so on.<br />
<br />
You'll be required to actually write code and <i>run</i> it! yes, the code you write is then executed in a web "interpreter" (modified for educational purposes) and the output displayed on screen. In a section is also possible to write to files and have their contents shown on another tab.<br />
<br />
I'd encourage you to start from it if you never saw Python and you're willing to learn if from the ground up.Sandro Tosihttp://www.blogger.com/profile/13017373086527472437noreply@blogger.com3tag:blogger.com,1999:blog-462006525194985726.post-38060381874594511932012-11-18T13:22:00.003-05:002012-11-18T13:22:37.493-05:00Spending a Sunday on CodingBat.comI've played a bit with <a href="http://projecteuler.net/">Project Euler</a> but all of their problems are math-centric, which is nice but not exactly what I'm looking for: some real-world programming problems to <i>get back into the coding field</i>.<br />
<br />
So asking my friend Google, I found <a href="http://codingbat.com/">CodingBat</a>: it has a Python <a href="http://codingbat.com/python">section</a> with several tasks to complete. I must say they are some kinda trivial to solve, once you know some idiomatic Python code, but some are a bit more interesting. If you're a junior Python coder, or want to get a grip on the language, give it a look.<br />
<br />
Oh, and if you know some website that would give me some real-world programming coding problems (something that would be useful on the job, not just coding for fun), I would love to hear you.Sandro Tosihttp://www.blogger.com/profile/13017373086527472437noreply@blogger.com6tag:blogger.com,1999:blog-462006525194985726.post-66818632379466412222012-11-14T14:03:00.001-05:002012-11-14T15:31:55.169-05:00Project Euler - Problem 4Here's my solution to <a href="http://projecteuler.net/">Project Euler</a> <a href="http://projecteuler.net/problem=4">problem 4</a>:<br />
<br />
<pre class="prettyprint"># handy function to check if a number is palindrome
def is_palindrome(i):
return str(i) == str(i)[::-1]
# what's the max?
max_p = 0
# multiply all numbers `i` between 100 and 998, with all between i+1 and 999
for i in xrange(100, 999):
for j in xrange(i+1, 1000):
p = i * j
if is_palindrome(p) and p > max_p:
max_p = p
print max_p
</pre>
<br />
Comments are welcome.<br />
<br />
<b>Update</b>: fixed as per Alex comment.Sandro Tosihttp://www.blogger.com/profile/13017373086527472437noreply@blogger.com13tag:blogger.com,1999:blog-462006525194985726.post-57125724469691243602011-08-10T21:53:00.001-04:002011-08-11T06:20:55.348-04:00Mercurial: how to completely remove a named branchI like so much the git feature branch workflow, that in the early days of development on Python with Mercurial I created some named branches; well, that is something you should <b>not</b> do.<br />
<br />
In Mercurial, the changeset contains the branch name, so you cannot develop on a separated (named) branch and then merge on <i>default</i> and hope that branch goes away, because it will stay.<br />
<br />
What do I do now? Python Mercurial repository is quite big (around 200Megs) so I wanted to avoid to re-check it out. Thanks to the help of the folks on <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">#mercurial</span> (on <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">freenode</span> IRC network) I found my solution: <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">strip</span> the branch!<br />
<br />
Please note that <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">strip</span> is <b>dangerous</b>. Use it only as last resort, and mind you can lose data with it. That said, it's a very powerful tool :) My main aim was to remove completely those named branches, leave no traces, and lose the changes I made on them. Another important aspect is that I didn't merged those branches on default.<br />
<br />
So, how to get rid of a named branch:<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">$ hg strip "branch(${BRANCHNAME})"</span><br />
<br />
and re-iterate for all the branches you have, that's it. Now, to be completely sure they were removed and no spurious changes are in the repository, you can:<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">$ hg pull -u</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">$ hg outgoing</span><br />
<br />
and if it says "<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">no changes found</span>" you're sure that those branches are really gone.Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com6tag:blogger.com,1999:blog-462006525194985726.post-66909292312583327802011-08-01T18:13:00.000-04:002011-08-01T18:13:40.270-04:00And what am I now? A Python Core Developer!Yeah, since a couple of hours I'm officially a Python Core Developer (and <a href="http://www.python.org/dev/committers">this</a> confirms it, so I'm not dreaming!)<br />
<br />
I'm now in that mixed state in between the happiness and the fear I'll do stupid mistakes and I'll be ashamed of myself. But hey, i<i>t's only those who do nothing that make no mistakes</i>.<br />
<br />
Interesting days ahead, a lot of procedures to learn and get used to, hopefully also a lot of bugs fixed :) That's for sure, I'll go step by step, following the <i>better be safe than sorry</i> rule.<br />
<br />
At the end, I'd like to thank all the people at Python that made this possible, they are quite a number, so if I'd named them, I surely forgot someone, and it would be unfair! So well, you know who you are, and this big <b>THANK YOU</b> is yours :)Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com5tag:blogger.com,1999:blog-462006525194985726.post-30896944134546927462011-05-18T19:10:00.000-04:002011-05-18T19:10:49.899-04:00I'm going to EuroPython 2011I just got confirmation my company will sponsor me for EuroPython 2011 (thanks <a href="http://we.register.it/index.html?chglng=eng">Register.it</a>), so I'll be able to attend the whole week; a lot of amazing talks and the code sprints in the weekend: this is going to be a great time!<br />
<br />
Are you coming?Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com2tag:blogger.com,1999:blog-462006525194985726.post-57954466134766583182011-04-11T10:15:00.000-04:002011-04-11T10:15:47.951-04:00Python: group a list in sub-lists of n itemsA long list, and you want to process its items n at a time; easy, but how to split that list in sublists of n elements (except the last one, of course)?<br />
<br />
I looked a bit into the stdlib but it doesn't seem to exist anything I could use (oh, did I say I'm still on 2.4?) so I directed my research to Google, and found a nice <a href="http://code.activestate.com/recipes/303060-group-a-list-into-sequential-n-tuples/">recipe</a> at <a href="http://code.activestate.com/">ActiveState</a>, but it has the problem it discards the last list, if it has less than n items.<br />
<br />
Searching again, I got more lucky with <a href="http://countergram.com/python-group-iterator-list-function">this article</a>: it's a generator of tuples from a list, splitting every n elements and optionally return the last <i>semi-full</i> tuple. I slightly modified it to obtain:<br />
<br />
<pre class="prettyprint">def group_iter(iterator, n=2):
""" Given an iterator, it returns sub-lists made of n items
(except the last that can have len < n)
inspired by http://countergram.com/python-group-iterator-list-function"""
accumulator = []
for item in iterator:
accumulator.append(item)
if len(accumulator) == n: # tested as fast as separate counter
yield accumulator
accumulator = [] # tested faster than accumulator[:] = []
# and tested as fast as re-using one list object
if len(accumulator) != 0:
yield accumulator
</pre><br />
How would you have done it?Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com13tag:blogger.com,1999:blog-462006525194985726.post-58244544500897206252011-01-21T02:40:00.004-05:002011-01-21T02:46:52.024-05:00EuroPython 2011 @ Florence, IT - it's coming!Just when I was looking for a contact email to ask news about <a href="http://ep2011.europython.eu/">EuroPython 2011</a> dates... I noticed they are already there!! June 19 to 26 !<div><br /></div><div>Book your flights, reserve your vacations, hope to see you all there!</div><div><br /></div><div>PS: this year, <a href="http://www.pycon.it/">PyCon Italia</a> joins EuroPython in a single conference - the bigger the funnier</div>Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com0tag:blogger.com,1999:blog-462006525194985726.post-13069110743414532292010-12-29T03:37:00.002-05:002010-12-29T03:39:14.207-05:00Re: Converting date to epoch<a href="http://blog.snow-crash.org/2010/12/converting-date-to-epoch.html">Alexander</a>,did you even consider that I might need to convert a date to epoch in a python script? :)Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com2tag:blogger.com,1999:blog-462006525194985726.post-36797963914592713562010-12-28T17:00:00.002-05:002010-12-28T17:07:09.135-05:00Convert a date to epochit seems like an easy quest, ain't it? well, it took me far too long to get it done, so let just write it down, so that <i>maybe</i> I won't forget in 2 seconds:<pre class="prettyprint">>>> import time<br />>>> str = '2009-03-04'<br />>>> format = '%Y-%m-%d'<br />>>> time.mktime(time.strptime(str, format))<br />1236121200.0<br />>>> int(_)<br />1236121200<br /></pre><div>and here you have your epoch (if you just need seconds, use <span class="Apple-style-span" >int()</span>).</div>Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com6tag:blogger.com,1999:blog-462006525194985726.post-55674191350356649682010-10-20T14:54:00.002-04:002010-10-20T15:03:23.158-04:00Feeling welcome: Python, you're doing it right!It was for a very long time (I think back from PyconIT 2) that I wanted to contribute to python. About a month and a half ago I started reading all the documentation I could about development processes & workflows, mercurial stuff (I don't have commit right, so I prefer working on a DVCS than on SVN), bugs management and so.<div><br /></div><div>After all of this, less than month ago I started contributing very small patches; then when looking for "something to do" I found bugs that could be closed, in particular because they were already been fixed, and then last night R. David Murray proposed to give me "tracker privs", that moments after were granted \o/</div><div><br /></div><div>What can I say? Thank you! that's something making me feel like I'm doing something useful to the language I love, and even if the privs are "not that much", it's a sign of trust, which really makes me happy!</div><div><br /></div><div>As of now, I feel like I'm between "better be safe than sorry" and "it's easier to ask forgiveness than permission" mood, but we'll see how it goes.</div><div><br /></div><div>Python, you're making me feel welcome, and so, once again, thank you!</div>Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com0tag:blogger.com,1999:blog-462006525194985726.post-63298955880776929962010-09-17T09:53:00.002-04:002010-09-17T10:03:15.040-04:00HTTP requests specifying the Host header (in Python)Since it took me some time to find this solution, I think it might be worth to share it.<div><br /></div><div>When you have a web server listening on a single IP address but serving several domains, it's quite common to run:</div><pre>$ curl -H "Host: domain" http://ip_address/path/to/the/page.html</pre><div>if you need to view that domain directly pointing to the web server (so avoiding any balancers or network "magics" you might have in place).</div><div><br /></div><div>Well, the question is: how to do that in Python? I find my answer in the <a href="http://docs.python.org/library/httplib.html">httplib</a> module:</div><pre class="prettyprint">import httplib<br />conn = httplib.HTTPConnection("ip_address")<br />conn.putrequest("GET", "/", skip_host=True)<br />conn.putheader("Host", "domain.ext")<br />conn.endheaders()<br />res = conn.getresponse()<br />print res.read()<br /></pre><div>HTH</div>Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com3tag:blogger.com,1999:blog-462006525194985726.post-72286670693028786422010-03-26T05:41:00.003-04:002010-03-26T06:00:05.986-04:00I'm going to Pycon Italia 4Yep, I'll be there this year too (sadly I can't say it's my fourth time, since I missed Pycon1).<br /><br />I'm not that excited about the proposed talks, hey we don't need that much of Django :) I hope the invited speakers will surprise me, I'm confident the organization will do that.<br /><br />See ya there!Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com0tag:blogger.com,1999:blog-462006525194985726.post-2320441112295632432010-03-17T07:23:00.003-04:002010-03-17T07:31:03.818-04:00Check Nagios from the desktop: nagstamonI just discovered <a href="http://nagstamon.sourceforge.net/">nagstamon</a> and all the team fallen in love with it!<br /><br />I tried to use <a href="https://addons.mozilla.org/en-US/firefox/addon/3607">Nagios Checker</a>, the Firefox plugin to notify of any Nagios alert, but that doesn't play nicely with several opened windows (alerts are multiplied for the number of windows, since it seems everyone does the checks, not just one) and it tends to slow down Firefox, that's already quite slow per se :)<br /><br />The upstream author provides a Debian package, so promptly I wrote to him asking if he can consider maintain the package in Debian, with me as mentor/co-maintainer and so (it's in Python so I can that :) ); let's see how it goes.<br /><br />Give it a try, it's really simple and awesome!Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com6tag:blogger.com,1999:blog-462006525194985726.post-19155215327725861942010-03-05T18:45:00.006-05:002010-03-06T12:36:36.443-05:00Project Euler - Problem 14Inspired by <a href="http://slott-softwarearchitect.blogspot.com/">S. Lott</a> and his <a href="http://slott-softwarearchitect.blogspot.com/2010/03/fun.html">blog post</a> (and by the pure genius that <a href="http://xkcd.com/">xkcd</a> is giving us these days, <a href="http://xkcd.com/710/">today</a> included) I gave a look to <a href="http://projecteuler.net/">Project Euler</a> <a href="http://projecteuler.net/index.php?section=problems&id=14">problem 14</a>, that's about the <a href="http://en.wikipedia.org/wiki/Collatz_conjecture">Collatz conjecture</a>.<br /><br />The straightforward recursive solution:<br /><pre class="prettyprint">def collatz(n):<br /> if n == 1:<br /> return 1<br /> if n % 2 == 0:<br /> return 1 + collatz(n/2)<br /> else:<br /> return 1 + collatz(3*n + 1)<br /></pre>very rapidly converges to... an error:<br /><pre>RuntimeError: maximum recursion depth exceeded</pre>So I've recoded it a bit using a <span style="font-family:courier new;">cache</span> dictionary to store all the intermediate values in it:<br /><pre class="prettyprint">cache = {1: 1}<br /><br />def collatz(n, res):<br /> nn = n<br /><br /> while True:<br /> if n in cache:<br /> if nn != n:<br /> cache[nn] = cache[n]<br /> return cache[nn]<br /><br /> if n % 2 == 0:<br /> cache[n] = 1 + collatz(n/2, cache)<br /> else:<br /> cache[n] = 1 + collatz(3*n + 1, cache)<br /></pre>Now loping for all the numbers lower than 1 million we find the solution to the problem: the number with the longest path is 837799 with a path length of 524. The code runs in about 4secs.<br /><br />Since I got that <span style="font-family:courier new;">cache</span> dict around to play with, I graphed with Matplotlib (strange, ha ;) ) the frequencies of each path length:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_VYVH3k3q6t8/S5J50jf3DcI/AAAAAAAAAJY/aBL7v4kLExE/s1600-h/problem14.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 301px;" src="http://2.bp.blogspot.com/_VYVH3k3q6t8/S5J50jf3DcI/AAAAAAAAAJY/aBL7v4kLExE/s400/problem14.png" alt="" id="BLOGGER_PHOTO_ID_5445548843233381826" border="0" /></a>There are few short paths, several long paths but rare to occur, and most of the paths have length between 100 and 200 (more or less).<br /><br /><span style="font-weight: bold;">UPDATE</span>: I've removed <span style="font-family: courier new;">length</span> variable, not needed (left from a previous version of the code) and fixed the path length for 837799, wrongly reported.Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com12tag:blogger.com,1999:blog-462006525194985726.post-80629982755107303212010-02-03T06:11:00.005-05:002010-02-03T06:28:21.529-05:00Convert a time string (with microseconds) in a datetimeI struggled a bit with <span style="font-family: courier new;">datetime</span> & friends providing a <span style="font-family: courier new;">strftime()</span> that support <span style="font-family: courier new;">%f </span> (for microseconds output) but <span style="font-style: italic;">not</span> a <span style="font-family: courier new;">strptime()</span> . That's really boring and counter-intuitive, and luckily it was <a href="http://bugs.python.org/issue1982#msg75976">fixed</a> in 2.6:<br /><br /><span style="font-family: courier new;">$ python2.6</span><br /><span style="font-family: courier new;"></span><span style="font-family: courier new;">>>> import datetime</span><br /><span style="font-family: courier new;">>>> datetime.datetime.strptime('22:57:39.101941', '%H:%M:%S.%f')</span><br /><span style="font-family: courier new;">datetime.datetime(1900, 1, 1, 22, 57, 39, 101941)</span><br /><br />but on my servers I still have 2.5, so what to do?<br /><br />I found a <a href="http://stackoverflow.com/questions/531157/parsing-datetime-strings-with-microseconds/531234#531234">reply</a> on <a href="http://stackoverflow.com">StackOverflow</a> quite interesting:<br /><br /><span style="font-family: courier new;">$ python2.5</span><br /><span style="font-family: courier new;">>>> from dateutil.parser import parser</span><br /><span style="font-family: courier new;">>>> p = parser()</span><br /><span style="font-family: courier new;">>>> p.parse('22:57:39.101941')</span><br /><span style="font-family: courier new;">datetime.datetime(2010, 2, 3, 22, 57, 39, 101941)</span><br /><br />ok, it uses the current date (instead of 1900-01-01) but it's still has the microseconds correctly recognized (and since I need a time diff, I'm fine with that).Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com1tag:blogger.com,1999:blog-462006525194985726.post-56283351685044717892010-01-07T14:40:00.005-05:002010-01-14T16:26:35.416-05:00Is being pirated sign of success?I don't know (and I don't think so) but for sure it's less money in my pocket :)<br /><br />Anyhow, just the other day I found my <a href="http://www.packtpub.com/matplotlib-python-development/mid/171109cna1hk?utm_source=sandrotosi.blogspot.com&utm_medium=affiliate&utm_content=authorsite&utm_campaign=mdb_001536">book</a> was available for "free download" in a <a href="http://are%20you%20expecting%20me%20to%20post%20the%20link/?%20really?%20:%29">post</a> on a rapidshare forum.<br /><br />I don't bother too much, it just a strange feeling...Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com8tag:blogger.com,1999:blog-462006525194985726.post-2156426113675329932009-12-29T05:29:00.004-05:002010-01-14T16:24:49.274-05:00Matplotlib for Python Developers - Images available for downloadThis is a <a href="http://www.packtpub.com/matplotlib-python-development/mid/171109cna1hk?utm_source=sandrotosi.blogspot.com&utm_medium=affiliate&utm_content=authorsite&utm_campaign=mdb_001536">book</a> on a graphic library, so when they first told me it will be printed in black&white I was quite surprised and puzzled. The editor explained it was to reduce paper copy cost, and that the PDF version will still be in full color, but I would be quite upset if I bought the book and then discover it's black&white without knowing it upfront.<br /><br />Thus I've asked to at least let the images be downloadable from the book website, so that any reader (either for the paper or electronic copy) can see the pictures as if they're running the programs.<br /><br />The first request went ignored, but keep pushing got results: now images can be downloaded!! To get them, got the book <a href="http://www.packtpub.com/matplotlib-python-development/mid/171109cna1hk?utm_source=sandrotosi.blogspot.com&utm_medium=affiliate&utm_content=authorsite&utm_campaign=mdb_001536">webpage</a>, then in the "Code Download" section, and request the zip file: in it you'll find either the source code and the images.<br /><br />The pictures are quite big, because they are the same used for book production (so with specific dimensions and DPI) but you got colors now :)Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com2tag:blogger.com,1999:blog-462006525194985726.post-88375689992418967562009-11-21T12:21:00.006-05:002010-01-14T16:24:42.410-05:00Matplotlib for Python Developers - PUBLISHED!Some days are passed, but I'm still pleased to announce that<br /><br /><div style="text-align: center;">The first book about <a href="http://matplotlib.sourceforge.net/">Matplotlib</a> has been <a style="font-weight: bold;" href="http://www.packtpub.com/matplotlib-python-development/mid/171109cna1hk?utm_source=sandrotosi.blogspot.com&utm_medium=affiliate&utm_content=authorsite&utm_campaign=mdb_001536">PUBLISHED</a>!!<br /></div><br />It was a really nice experience, it offered me the possibility to work on Matplotlib, do some really interesting stuff, and I'm quite proud of it :)<br /><br />On the other hand, it was not a "straight" way: the effort I put in this was huge, practically I had to stop all other stuffs and projects I was working on (Debian included) and I was getting more and more tired as time passed. Also, sometimes Packt employees and actions were somehow problematic. but anyhow, the important thing is that THE BOOK IS OUT!!<br /><br />Now I got also a nice box about the book on the sidebar of this blog!<br /><br /><a href="http://www.packtpub.com/matplotlib-python-development/mid/171109cna1hk?utm_source=sandrotosi.blogspot.com&utm_medium=affiliate&utm_content=authorsite&utm_campaign=mdb_001536">Enjoy it</a>!!Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com13tag:blogger.com,1999:blog-462006525194985726.post-78840884536386744942009-09-07T05:54:00.004-04:002010-01-14T16:24:36.695-05:00The beast is quite doneAt the end, I made it: the <a href="http://sandrotosi.blogspot.com/2009/01/what-would-you-like-to-see-in-book.html">book</a> is in <a href="http://www.packtpub.com/matplotlib-python-development/book">pre-order</a> phase!! yayyy<br /><br />I'm at the end of reviewing chapters, so I can see the light at the end of the <span style="font-style: italic;">tunnel</span> :)<br /><br />Probably I'll be able to sleep more than 4/5 hrs at night and have additional spare time to work on the projects I've neglected in these monthsSandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com4tag:blogger.com,1999:blog-462006525194985726.post-10768414284992960172009-06-22T10:13:00.003-04:002009-06-22T10:48:24.291-04:00Web scraping with Python for fun and profitWeb is everywhere, we know. It is also used more and more to present information to a wide audience. Sadly, it is commonly the <span style="font-style: italic;">only</span> way data is presented...<br /><br />That said, we need to get that info; the process of extracting information from web pages is knows as <span style="font-style: italic;">web scraping</span>, and note that's is a very fragile process: every time the webpage changes, it's likely you'll have to modify the code that parses it.<br /><br />The probably most famous Python module to do web scraping is <a href="http://www.crummy.com/software/BeautifulSoup/">BeautifulSoup</a>. While it might be nice for simple webpages, I found it really hard to get something done for more complex pages, in particular with those with JavaScript embedded.<br /><br />Thanks to Ian <a href="http://blog.ianbicking.org/2008/12/10/lxml-an-underappreciated-web-scraping-library/">blogpost</a>, I discovered how nice is to use <a href="http://codespeak.net/lxml/">lxml</a> to do <a href="http://codespeak.net/lxml/parsing.html">web</a> scraping, in particular in <a href="http://woz.thebigbluesky.us/a_curious_absurdity/2009/02/08/web-scraping-with-lxml/">association</a> with <a href="https://addons.mozilla.org/en-US/firefox/addon/1843">Firebug</a> Firefox addon: it's just a simple process of:<br /><ol><li>take the page;</li><li>generate the <span style="font-family: courier new;">lxml</span> tree;</li><li>with Firebug find the XPath to the element you need;</li><li>loop / parse / have fun :)<br /></li></ol>If you find in need to web scrape a page, give <span style="font-family: courier new;">lxml</span> a try: you'll be surprised and satisfied!Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com6tag:blogger.com,1999:blog-462006525194985726.post-16962081905920819252009-05-28T04:28:00.004-04:002009-05-28T05:12:20.916-04:00Update on the Matplotlib bookSome people asked me how's the <a href="http://sandrotosi.blogspot.com/2009/01/what-would-you-like-to-see-in-book.html">book writing</a> is going. Ah you're right, it's a loooong time I didn't say anything of the progress, and here it is.<br /><br /><span style="display: block;" id="formatbar_Buttons"><span class="on down" style="display: block;" id="formatbar_CreateLink" title="Link" onmouseover="ButtonHoverOn(this);" onmouseout="ButtonHoverOff(this);" onmouseup="" onmousedown="CheckFormatting(event);FormatbarButton('richeditorframe', this, 8);ButtonMouseDown(this);">I've just turned the half of the book: about 10 days ago I've sent the 5th chapter (out of 10) and up to now I've covered this (high-level) contents by chapter:<br /><br /></span></span><ol><li>installation & setup<br /></li><li>first contact with mpl</li><li>some more stuff (like graph types)</li><li>OO style and some advanced things</li><li>GTK embedding</li></ol>6th (and current) chapter is about Qt, so even KDE guys will be happy :)<br /><br />I found several problems when working with GUI design programs: both Glade and Qt Designer made me scream a lot; but probably it's just me that I'm not so used to GUIs :)<br /><br />Other arguments will be: Wx, web, real use cases.<br /><br />In particular for the last part (real cases) I'd like to hear some proposals from you. I've already got something in mind, but users opinion will help me direct my work better.<br /><br />Sorry, I've got to "drop/reduce" the science chapter (it was superseded by the real use-cases one) since I don't think this is the right place for it. Of course, a couple of "science examples" might come into the mentioned chapter, but your proposals have to be at a low-medium level.Sandro Tosihttp://www.blogger.com/profile/17077191422205823991noreply@blogger.com0