back to indexpythonrunscript - Answer.AI dev chat #3
00:00:00.000 |
Hey, everyone. This is Alexis from Answer.ai. This video is one of our dev chats. These 00:00:07.120 |
are internal/external chats that we do about anything that we're working on and we want 00:00:11.160 |
to share with other people. This is about a tool I made called Python Run Script. It 00:00:17.080 |
lets you define single file Python scripts that declare their dependencies internally 00:00:22.640 |
in comments. So, you can just run them without having to manually set up or manage a Conda 00:00:28.420 |
environment or a virtual environment or a VM environment or whatever. I've wanted to 00:00:34.000 |
put this little comment right now in front of the video because some of the things in 00:00:39.100 |
the video are a bit out of date. So, one thing is it's called Python Run Script, not Python 00:00:43.600 |
Script or whatever I refer to it as in the video. Another thing is it's done. It's in 00:00:47.600 |
a GitHub repo. You can go check it out there, grab the binary, or you can install it by 00:00:53.360 |
just pip installing Python Run Script. And some of the syntax that we talked over ended 00:00:58.680 |
up a little different. It uses markdown fences instead of yaml fences to let you declare 00:01:04.420 |
your dependencies. You can use requirements.txt or environment.yaml or conda install specs 00:01:09.520 |
and put them in there. And also it has a dry run mode or verbose mode and the other amenities 00:01:15.320 |
you'd expect from a command line tool. It works on Linux and Mac OS. In addition to 00:01:21.020 |
talking about this tool, we also talk more generally about scripting languages and what 00:01:26.760 |
makes them good or bad. So, I hope you find this interesting, and thanks. 00:01:32.560 |
>> Okay. Now it's working. >> There we go. Now we're recording. Hello, 00:01:40.000 |
gentlemen. Okay. So, I thought I would talk about something that I've been hacking on 00:01:51.440 |
>> Oh, right. Sorry. I'm Alexis. >> Hi, Alexis. 00:01:55.240 |
>> Hello, everybody. I'm at Answer AI. This is one of our Dev Chats, which may or may 00:02:02.920 |
not be published. So, might as well introduce ourselves. Jeremy, who are you? 00:02:10.880 |
>> They know me because I've done two of them already. 00:02:12.640 |
>> Okay. Well, Jono, what about you? >> Yep. I'm also at Answer AI. I think maybe 00:02:17.800 |
in some past videos on the channel. If not, also R&D, same job title as everyone. So, 00:02:23.240 |
that should be enough for now. >> All right. So, I just wanted to talk to 00:02:28.160 |
you guys about something that I started on Friday afternoon when the brainstorm hit me. 00:02:35.160 |
And now it's mostly working, although it's not prettied up yet. But I'm actually quite 00:02:38.880 |
happy with it. So, I wanted to get feedback from you both on, I don't know, ways to improve 00:02:44.840 |
it, if it would be useful to you, or just if it's interesting. 00:02:48.520 |
>> So, what was the brainstorm? What was the problem your brain was trying to solve? 00:02:52.960 |
>> So, I have a very opinionated brain. And the problem I was trying to solve, which I've 00:02:59.640 |
tried to solve before, is to try to find an adequate scripting language. Also, just an 00:03:08.200 |
easy way to get started on development. Now, I started writing a mini rant about the whole, 00:03:14.640 |
you know, what it means for a scripting language to be adequate, which I haven't published 00:03:21.320 |
yet. But I'm aware that the moment you say something like best solution for scripting, 00:03:26.040 |
you're going to get a bunch of responses. Like, hey, you should just use Bash because 00:03:30.020 |
Bash is everywhere. Or someone will say, just use Python because, you know, Bash is terrible 00:03:34.800 |
and you have to use Python anyway because it's the best thing for the data science stack. 00:03:38.760 |
That's a better language than Bash. All those things are true. 00:03:41.800 |
>> I'm in the just use Perl category for what it's worth. 00:03:45.400 |
>> You're right. Or just use Perl. >> I think I should probably learn Ruby. 00:03:49.560 |
>> I think Ruby came and went. Well, I'm sure that's not true. Don't send me an email. 00:03:54.800 |
>> Careful! You don't know who's going to be watching this. 00:03:57.960 |
>> It's great for web things. And I have published a Ruby gem, so I can't call it a Ruby hater. 00:04:03.340 |
Or if you keep going down this line, you'll get reactions like, what's wrong with you? 00:04:08.340 |
You're crazy. You're overthinking it. All things are relative. There is no best language. 00:04:13.020 |
Just be practical. Turn off your brain. That's not -- I understand that objection. I just 00:04:19.060 |
totally reject it. It's not the way I operate. So here are the criteria that I started putting 00:04:26.060 |
together in my mind for what I think would be a kind of adequate, you know, scripting 00:04:29.780 |
language or a property you really want to have in any language you want. First of all, 00:04:35.300 |
a script means a single file. There's a lot of tasks where you want to be able to write 00:04:39.820 |
a single file program quickly in order to get things done. This is what we like about 00:04:47.520 |
Bash. Also, an adequate scripting language should be one where it's good for the sort 00:04:58.500 |
of things you do with scripting. So what do we mean when we talk about scripting? Often 00:05:01.860 |
we mean file manipulation, some text manipulation, and some process manipulation, like launch 00:05:07.900 |
this process, launch that process, move these files around. This is what Bash is really 00:05:12.380 |
good for. >> I don't know if you mentioned it, but a 00:05:14.900 |
bit of network stuff, probably like grabbing something -- 00:05:17.620 |
>> Perling stuff or pulling stuff down and then doing things with it. So that's sort 00:05:22.380 |
of the domain of scripting and where some languages, you know, might be really good 00:05:27.940 |
in a general way, like I'm fond of Swift, they often fall down on scripting because 00:05:32.740 |
some of their APIs are very verbose for these routine operations. 00:05:36.140 |
>> And ideally, deployment would be attach it to an email and send it to somebody. 00:05:41.820 |
>> Yes, yes. So this is another part of an adequate scripting language. I can even -- why 00:05:46.860 |
not? I can share the sort of draft that I started writing on this, which you can see 00:05:53.860 |
I'm now sort of speaking from vaguely when I talk about what we mean by an adequate scripting 00:05:58.860 |
language. So easily deployable is one of these things. So I've had the experience a number 00:06:04.500 |
of times where I'm roaming around on the Internet looking for a piece of software I might use 00:06:09.420 |
for something that would be useful, and then I find some GitHub repo, and it looks beautiful, 00:06:13.740 |
just does it. It's great. And then it's like, just, you know, launch your NPM and do your 00:06:18.380 |
node and do your package.json. It's like, that's not my religion. I don't know that 00:06:22.340 |
stack very well. I don't want to learn it very well. I've gotten other things -- 00:06:26.460 |
>> Just to mention, your window might be quite small or something, because it looks pretty 00:06:30.380 |
pixelated over here. No, it's like your font size is fine. But, yeah, I think your window 00:06:42.020 |
>> Small, because it expands it to fill our window. 00:06:44.620 |
>> Okay. It's probably not the right geometry. >> It's probably like a large window with 00:06:49.020 |
normal sized font. That way we'll get, you know, high resolution. 00:06:58.100 |
>> Good? Okay. So easily deployable. This is another big one. And ideally for this easily 00:07:05.180 |
deployable property, you want to have one file, and then you give another person the 00:07:09.260 |
one file, and then they can just run the damn thing. You don't need to give them an instruction 00:07:13.700 |
manual on how to understand Python virtual environments, or exactly what a Node project 00:07:18.660 |
is, or why you should be using RBMs instead of RubyMs, instead of gem explode or whatever. 00:07:27.300 |
And obvious things, too. You want it to be cross-platform. You don't want to have to 00:07:36.980 |
learn the subtleties of exactly how this command is different on Linux versus different on 00:07:42.100 |
Mac, before you can hand it around to your friends and family. And you want it to be 00:07:47.140 |
not a crappy language. So decent syntax is part of that. 00:07:50.940 |
>> And I will say Perl is definitely ticking all the boxes so far. 00:07:57.580 |
>> Yep. Perl is on everybody's computer already. Single file, yes. Easily deployable, yes. 00:08:06.260 |
And the syntax is, like, just basically the same as Bash. If you want to run a process, 00:08:16.140 |
you stick it in backticks. The result of that process ends up in the variable that you passed 00:08:20.840 |
it to. It has, you know, regular expression, language support directly, a library. 00:08:32.060 |
>> So maybe Perl already -- >> And it's got a great standard library, 00:08:34.260 |
so, yeah, your scripts will be cross-platform. And I would add another one, which is, like, 00:08:41.480 |
you don't have to learn any language. Maybe that would be another thing to list here. 00:08:45.300 |
And since no one knows Perl anymore, it would fail on that. 00:08:49.100 |
>> Yeah. No, that's also a reasonable one. Although perhaps it's a temperamental weakness 00:08:56.140 |
of mine that I wouldn't think of adding that. So another one I would say is that you want 00:09:02.660 |
to have a good prompt, a good interactive prompt. And that's one that we -- that a lot 00:09:07.980 |
of nice languages can sometimes underperform on. And it's also one of the strengths of 00:09:12.060 |
Bash. Like, the shell is already your interactive prompt, so much so that you don't -- 00:09:15.220 |
>> Yes. It is. Sorry. >> All right. Is audio good again? 00:09:24.940 |
>> Yep. >> So I'll just briefly say, like, why some 00:09:28.340 |
obvious solutions don't work. >> Oh, we've lost you again. It's like -- I 00:09:35.300 |
think there's, like, a wire that's loose or something. Because, like, you -- suddenly 00:09:40.060 |
we just don't hear you at all. >> All right. Let me -- I'm on the wireless, 00:09:45.980 |
so that seems unlikely. >> Yeah. I was just wondering if, like, the 00:09:48.300 |
boom mic has got a loose wire in it or something. I don't know. It's like it's just -- 00:09:52.340 |
>> How about -- >> -- talking, everything's fine, and then 00:09:55.060 |
suddenly it's, like, gone. Most of the time, it's fine. We can tell you what's up. 00:09:59.740 |
>> I'll show a bunch of stuff in the background, and maybe that'll help. All right. Here I 00:10:07.620 |
am. So just to kind of recap why some things don't -- don't solve this problem as well 00:10:14.660 |
as we wished it would. And did I just close Emacs when I was having my frenzy of -- 00:10:19.980 |
>> And stop sharing your screen. >> -- stop sharing your screen, so -- 00:10:23.060 |
>> Okay. All right. I'll bring it up again later. But just to say, like, why some things 00:10:28.900 |
don't meet this as well as they might. And the last thing is external dependencies. So 00:10:34.780 |
it's all very well and good if you have this nice single file script. But if having a single 00:10:38.620 |
file script means you're confined to using the built-in standard library, well, you've 00:10:44.300 |
kind of already lost now. Because now you've exploded the other properties. Like, let's 00:10:49.220 |
say I want to do something in Python, for instance, fairly modest. Like, I want to handle 00:10:53.220 |
YAML. As far as I know -- I could be out of date with this -- YAML isn't in the standard 00:10:58.540 |
library. So now I'm talking about either building my own YAML parser or emitter and putting 00:11:05.820 |
it in my file. Now I've lost convenience. Or I'm using an external library. And now 00:11:10.460 |
I need to explain to someone else how to make sure they can install an external library. 00:11:21.060 |
So why some languages don't meet these properties right away. The lack of easy integration of 00:11:30.100 |
the external library, that one you lose right away for a lot of them. So that's a shame. 00:11:38.020 |
Languages that you might think would be -- even if it's not a very good language, it's sort 00:11:41.380 |
of everywhere. Bash. You don't have the cross-platformness, really. Because the Bash standard library is 00:11:46.700 |
actually all the external commands that are on your Unix system. 00:11:50.860 |
And those annoyingly are different in subtle ways from Mac OS to Linux. If you're writing 00:11:55.740 |
a non-trivial script, you start becoming a specialist in the fact that the date command 00:12:00.260 |
is going to be a little bit different. And the grep command is going to take different 00:12:04.340 |
arguments. It's just nonsense. Python and Node have this problem that the package management 00:12:12.660 |
system is a thing where you kind of need to create a whole directory around your script. 00:12:18.420 |
So you've already lost the nice single file property. And you need whoever you're giving 00:12:23.080 |
it to to know how to manage local environments. Or to be such a guru that they have one vast 00:12:29.180 |
omni environment that they maintain in a state of cutting-edge excellence and consistency 00:12:34.620 |
and self-compatibility, which not everyone knows how to do. 00:12:39.700 |
Some languages that almost do this really well, I'd say, are Go and Rust. Why? Because 00:12:46.860 |
they actually can produce a single static-linked executable. So whatever complexity you went 00:12:52.780 |
through when you were writing the thing, you can't often just give someone a damn artifact 00:12:56.660 |
and they can run it. They don't need to get a PhD in your build system in order to use 00:12:59.980 |
the thing, which is a beautiful, beautiful property. That's why you have all these great 00:13:04.260 |
command line tools now that come out of the Go and Rust community. Because they make something 00:13:09.900 |
and then everyone can use it. And we don't need to care how it was made. Whereas that 00:13:13.580 |
can't be said for a lot of other tools, unfortunately. 00:13:18.660 |
So that's the kind of way I think about the problem. And then I'll show you solutions 00:13:23.980 |
that I've run into. Two or three that struck me as interesting. And then my version of 00:13:28.180 |
it in Python. And you guys can let me know maybe how it could be improved. 00:13:33.940 |
So the original idea-- let me share my screen. All right. Can you see the browser? So-- 00:13:53.160 |
OK. So I was originally inspired by this library from years ago by a brilliant guy named Max 00:14:01.500 |
Howell, who's responsible for the homebrew package management system, among other things. 00:14:08.460 |
And he did a lot of work in the Swift language. And he came up with this thing called Swift 00:14:16.020 |
Yeah. It's a brilliantly tasteful little piece of engineering. Swift is nice. You can write 00:14:22.540 |
a single file script in Swift. But then Swift is crappy because you have a bunch of dependencies. 00:14:28.240 |
You need to have a package file. You need to have a directory. You need to name them. 00:14:35.020 |
But with his thing, instead of having your shebang line in your normal Swift script be 00:14:40.660 |
this, you just change it to Swift sh. And then you write Swift as usual, except you 00:14:47.260 |
add special comments that come after the normal Swift import statements. So this comment says 00:14:53.260 |
that the Promise Git library can actually be got from the GitHub account associated 00:14:58.660 |
with Max Howell. And this script needs a version 6.5 or greater. And you can get more involved 00:15:06.040 |
with it if you want. You can have fairly elaborate statements of version dependencies. 00:15:12.780 |
So in this way, you can write a single file script that actually can have half a dozen 00:15:17.480 |
external dependencies with pinned versions if you want. And when you run the script, 00:15:22.360 |
it will just work. It'll do all the compiling somewhere else you don't see it. And you just 00:15:26.280 |
have the magic of, I give someone a single file. And as long as they have this Swift 00:15:30.240 |
shell malarkey installed, then they can just run that file. And the first time they run 00:15:35.160 |
it, it takes a while because it's fetching all this stuff and it's compiling. But then 00:15:38.320 |
the second time, it just runs because you have an actually efficient compiled executable. 00:15:48.020 |
Then the Rust folks never miss a beat these days. There's a similar thing in Rust called 00:15:54.820 |
Rust Script. And it's exactly the same idea. You need to install Rust Script. That's actually 00:16:00.420 |
not so great to install. You've got to go and install it with an installer. It's not 00:16:05.020 |
just a binary you put in a magic place. But then once you do, it's the same gimmick or 00:16:13.260 |
the same act of genius. You just replace your shebang with Rust Script. And then you have 00:16:18.460 |
this comment block that comes right after Rust Script that states your Rust dependencies. 00:16:22.700 |
OK, I need time version 0.1.2.5. And then once you've done that, you've magically created 00:16:29.080 |
a single file using Rust that can exploit the whole Rust dependency ecosystem and is 00:16:34.100 |
dead easy to run. You just run it and it goes. That's great for development if you just are 00:16:38.760 |
getting something started with something small. And it's great for distribution. You just 00:16:43.060 |
give someone the file and they don't need to learn about Rust. They just do it. 00:16:46.460 |
I wrote a C# version of this about 20 years ago, which was great. That's in my insurance 00:16:54.020 |
pricing company. And we just give it to clients and they would use it to write insurance pricing 00:17:00.660 |
scripts. I think there might be a somewhat more official way to do it in C# now. 00:17:07.500 |
One would think there might be. So basically, I thought this should exist in Python because 00:17:15.220 |
I don't know if everyone here agrees, but I'd say Python has-- let me change the screen 00:17:24.460 |
I'm sharing. How do I do that? Where's my stop sharing button? OK. Because in my opinion, 00:17:36.120 |
one of the-- and OK, we're back in Emacs. And let me make the screen bigger. So it's 00:17:44.660 |
a reasonable size again, Jeremy, in terms of legibility? Yeah. Because the Python packaging 00:17:54.620 |
and distribution story, in my opinion, is terrible. Maybe it's great if you really know 00:17:59.460 |
your way around it. But it takes a while to realize all the different things that are 00:18:03.720 |
out there and which ones are redundant and which ones are official and which ones are 00:18:07.860 |
good and which ones are bad. And every time I step away from the language for years and 00:18:13.260 |
come back, I feel like I need to recheck to see if things are-- what the situation is. 00:18:18.300 |
And my understanding of the current situation is that there's two things that work and they 00:18:23.300 |
are all you need. If you don't need anything complicated, if you don't need anything that 00:18:28.940 |
has complicated native dependencies, then you can do everything with Venv. And you probably 00:18:35.340 |
should because Venv and Pip come built in. And that will get you everywhere you need 00:18:41.820 |
to go in terms of creating a contained environment and installing everything in a contained environment 00:18:46.700 |
and working from it. And that's not enough. Because if you are doing interesting machine 00:18:53.940 |
learning stuff, for example, or things that have parts of the data science stack, the 00:18:58.340 |
fact is not all of that can be packaged with Venv. And people who think so usually think 00:19:03.340 |
so because they just haven't had to use those dependencies. So they haven't run into those 00:19:06.620 |
cases yet. But when you hit those cases, then the answer is Conda. You don't need to like 00:19:12.140 |
it, but that seems to be the truth. So my current-- 00:19:15.340 |
It's not bad. It's not bad advice. For what it's worth, I would say, actually, you should 00:19:22.740 |
use Miniconda regardless. On Windows, if you run Python on a new Windows box, it's a wrapper 00:19:37.820 |
which basically points you to something that lets you install it. Like it's not already 00:19:41.220 |
there at all. On Mac, if you run Python, you're running the system Python, which Apple strongly 00:19:47.380 |
asks everybody not to use for anything other than letting them run system stuff. And on 00:19:53.100 |
Linux, it's pretty likely you've got a really old Python, you know, if you're using Ubuntu. 00:20:01.860 |
So I would tell people just use Miniconda. That way, you've got your own Python, and 00:20:07.780 |
you can still use Venv if you want to. But, you know, now it's just like one solution 00:20:13.300 |
for everybody. So just use Miniconda and just use environments. 00:20:17.780 |
I've only ever used Miniconda. I haven't used the whole sausage before. I think your knowledge 00:20:25.100 |
of this is much better than mine. So everyone, you should listen to Jeremy's advice. But 00:20:30.820 |
if you have an allergy to Conda, and you know you don't need the data science stack, then 00:20:35.620 |
it's my understanding that you can get by with just pip and VM. 00:20:38.380 |
You probably can get by. The other thing I'd say is if you think you have an allergy to 00:20:42.940 |
Conda, you probably have an allergy to Anaconda as it existed two or more years ago, at which 00:20:53.460 |
point it was slow and awful. And it's actually now fast and nice. So your allergy may have 00:21:04.260 |
Yeah. And also, if I understand right, Miniconda now uses Mamba as its dependency resolver. 00:21:11.260 |
Kind of. It uses Mamba's algorithm. But you don't ever have to think or know about that. 00:21:17.020 |
So it's actually, yeah, it's using LitMamba behind the scenes, which uses a proper fast 00:21:25.340 |
OK. Yeah. So maybe some people haven't touched it for a while, have a memory of it being 00:21:31.060 |
Yeah. It used to be very, very annoying. But nowadays, it just works. And it's quick. 00:21:36.220 |
So speaking of just works, why don't I show you what I have sort of working right now? 00:21:39.420 |
And I can get your opinion on what would be a maybe tasteful way to improve it. So based 00:21:45.740 |
on my picture of what one actually needs these days, being sometimes Conda and sometimes 00:21:51.700 |
just PIP and VM, I ultimately-- let's see what the latest version of this thing is. 00:21:58.460 |
Just one other thing to mention, if you do use Conda, you can still use VM. So if you 00:22:08.020 |
want to-- if for some reason, Conda environments are not for you, that's totally fine. You 00:22:15.140 |
can just use VM in all situations except the one that Alexis mentioned, which is you want 00:22:21.660 |
more complicated binary things to install, like a compiler framework or compiler toolkit 00:22:37.220 |
Yeah. So it's funny you mention that, because I've tried to cover both cases in the way 00:22:45.060 |
this thing works now based on my understanding of what's sometimes necessary and what's always 00:22:50.820 |
necessary. So the point you're making, Jeremy, is that if you create a Conda environment, 00:22:58.460 |
once you're within the Conda environment, then you can then run Conda install, and you'll 00:23:01.820 |
be installing packages that are Conda packages managed through Conda's distribution repos. 00:23:07.300 |
But once you're in the Conda environment, you can also just run PIP install and install-- 00:23:11.860 |
And you don't even need to be in a Conda environment. Once you've installed Conda, you're always 00:23:17.180 |
in an environment called the base environment, so you can actually never think about it. 00:23:21.580 |
You can forget about the fact you're using Conda or Miniconda entirely. You can use nothing 00:23:27.940 |
but PIP. You can use nothing but VNV. And your life will be just fine. You'll just be 00:23:33.180 |
using a recent Python version that's installed into your home directory and therefore is 00:23:39.820 |
up to date and doesn't upset your Mac and doesn't require sudo and so forth. 00:23:45.420 |
You should definitely be using one of those. You don't want to use the system Python, because 00:23:48.460 |
it's actually there for the system to use. It's not there with the intention that you 00:23:51.700 |
would build on top of it and install new dependencies into it. Because at any given point, Apple 00:23:57.820 |
might decide to upgrade it, change things around, and you don't want to be destabilizing 00:24:03.540 |
All right. So here's how this will work. I've got a couple test scripts here that I was 00:24:10.940 |
using to test it out. So I'll show some of the cases. So very simple example would be 00:24:20.100 |
one where you have a script and it has no dependencies at all. Here's a very boring 00:24:32.420 |
script. And here you can see the shebang is something I'm now calling VM script. But I'll 00:24:42.020 |
>> I'm just going to tell people what /usr/bin/env is, because a lot of people are confused about 00:24:48.860 |
that. So you don't have to use that. It's just a thing which, I don't know, it's kind 00:24:55.140 |
of a best -- I guess, you know, it's trying to find the correct place to find that from. 00:25:01.100 |
You could avoid that and just directly write the full path of your combo script, too, if 00:25:09.460 |
>> Yeah. All right. So the script I wrote, the latest version of it, is now -- this is 00:25:17.740 |
the part that needs cleaning up. This one right here. And what it will do is when it 00:25:29.980 |
reads a script, it will parse a script looking for a dependency block. A dependency block 00:25:43.980 |
is a formatted set of comments which may specify conda commands to run in a new conda environment. 00:25:59.700 |
And may specify the exact text of a requirements.txt file which will be pip installed, either in 00:26:18.900 |
the conda environment or else in a VM. So, for example, I've got my test scripts here. 00:26:31.660 |
I feel like I've let everyone into my house before I cleaned up. It's very embarrassing. 00:26:39.940 |
If you look at this script, for instance, this is the dependency block. The conda part 00:26:48.700 |
of the blocks always starts with a header which is conda commands.source. Because if 00:26:53.940 |
you were actually in a conda environment, you would source those commands in order to 00:26:58.700 |
do your installations. And then the things that you might only want to pip install are 00:27:04.980 |
in here, introduced with a header, requirements.txt. And this text here in the lines under requirements.txt 00:27:12.140 |
will literally be the text of a requirements.txt file that's used. And then Python 3 m pip install 00:27:20.820 |
-r requirements.txt will be run to install that. So, with this script, for instance, 00:27:27.540 |
if we run it, and let me put this in the - put my thing in the path here. All right. So, 00:27:57.360 |
the one I was looking at was test script conda requirements. Make sure my latest version 00:28:02.580 |
is in the path. Yes, it is. Move this chunk out of the way. So, I'm invoking it now by 00:28:13.780 |
calling the script. But because it's in the shebang, you wouldn't need to do that in order 00:28:17.800 |
to run it. >> Let's do it the cool way, then. 00:28:22.100 |
>> All right. Let's do it the cool way. So, let me make sure I've updated this to be - so, 00:28:32.520 |
just to recap what Jeremy was saying, people haven't used this before. This line in the 00:28:37.060 |
beginning is what tells the operating system what interpreter to use to run the file. So, 00:28:43.680 |
this file's been marked executable. Let me make sure I have it here. Conda and requirements. 00:28:50.780 |
Yeah, there's the X there for the executable bit. So, if I just run the script, conva script 00:28:57.100 |
2, sorry, I run test script, conda and requirements, then the operating system will read this line. 00:29:08.780 |
It'll say, okay, I got to go find this thing in the environment. Because I put it in the 00:29:13.580 |
path, it will be in the environment. It will then run my conva script 2 and pass in this 00:29:20.580 |
file test script conda requirements as the first argument to run it. And when I do that, 00:29:26.620 |
I've got it doing - well, there it ran very quickly, because I'd already cached the building 00:29:32.980 |
that it did. But I have it doing a lot of debug logging where it says - it parsed it, 00:29:38.660 |
it found that the dependency block implies the script will need conda. It then went into 00:29:43.620 |
a cache directory that's kept out of the way where it found the conda environment defined 00:29:48.460 |
by that directory. >> Okay. So, even though that's called VN skipped cache, I shouldn't 00:29:52.300 |
be confused. That's actually - >> Yeah, no, that's just the naming that I need to update 00:29:56.700 |
on where to put it. But let's get - we can go look at those cache things, erase them, 00:30:02.740 |
and then see it do the thing of figuring out what to do the first time. That's much noisier. 00:30:08.220 |
So, I'm calling it VN script cache, but I'll erase the cached environments now. And those 00:30:23.620 |
caches - those alphanumeric blobs were MD5 hashes that were based on the dependency block. 00:30:31.060 |
>> So, there's no fanciness, like I know some systems will - oh, you know, if you only changed 00:30:39.540 |
one of the pip requirements, there's no reason to, like, create a whole new conda environment 00:30:43.460 |
and download PyTorch again and all of that. It'll just update the one package. >> Well, 00:30:47.420 |
that won't happen anyway, because conda's very smart. So, first of all, conda stores 00:30:53.500 |
all downloaded packages in a packages directory. So, it won't have to re-download anything. 00:31:01.300 |
And the packages directory is stored, I think, in the base environments location. So, it 00:31:07.660 |
shouldn't be re-downloading any of those things. And then, secondly, although it looks like 00:31:16.300 |
it's using up a lot of space to have a whole second copy of Python and stuff, it's actually 00:31:21.380 |
using hard links. If you've got that installed elsewhere in another environment or in your 00:31:26.660 |
base environment. So, it's pretty smart. >> Cool. >> Yeah. So, this is - so, now it just 00:31:34.900 |
actually ran and did the thing. And I haven't silenced the output by capturing standard 00:31:38.980 |
out or dumping it. So, that's why it's so noisy. But as you can see here, it ran through 00:31:45.900 |
and installed the bits that were needed for conda, created a conda environment associated 00:31:51.940 |
with this directory only, did the conda installs, and then it also did the pip install into 00:31:59.660 |
that. And because conda also lets you specify the version of Python, this effectively ends 00:32:09.420 |
up being a way that you can, in your Python script, specify and ensure that it's run by 00:32:13.300 |
a specific version of Python, rather than have that be information that you communicate 00:32:17.980 |
out of channel and that someone else needs to keep track of. If you want to go see what 00:32:22.260 |
it's done in that developer directory, you can see there, it's now created a new entry 00:32:30.060 |
in that cache. And at the moment, I just write literally down here the conda commands that 00:32:36.380 |
were detected. Oh, interesting. I also wrote the requirements thing in there. But this 00:32:41.140 |
is just put here for information. It's not actually run. And then here's the stuff that 00:32:47.380 |
conda actually put in place. >> I can see it's got a little error there. 00:32:48.900 |
I can see in line 137, underneath, it's complaining about requirements.txt command.found and --prefix 00:32:55.500 |
command.found on line 139. >> Oh, right. Good point. So, my parser is 00:33:00.340 |
picking up the requirements.txt incorrectly. So, I should fix that. 00:33:08.620 |
>> It'll be fixed by the time somebody else watches this video. 00:33:13.260 |
>> Yes. And if we weren't using conda, if we only had -- let's look at another example. 00:33:18.980 |
Well, if you have a script with no dependencies, it's just going to run like a normal Python 00:33:27.100 |
script. Let me see if I can find that. Variant requirements. Yeah. So, this is had test script 00:33:44.020 |
no deps. Yeah. Chmod. >> I haven't seen chmod plus before. If you 00:34:00.140 |
>> U plus x, does it default to u and x? Or it defaults to ur, x, w? 00:34:06.300 |
>> You got me. That was a typo. I don't know what it does. 00:34:08.660 |
>> I'm surprised it didn't spit out an error. It must have done something. Maybe it added 00:34:13.740 |
nothing at all to no groups at all or users. >> Yeah. Or here's an example where it only 00:34:19.260 |
has a requirements.txt file. So, let's see that one go. 00:34:32.060 |
>> Core kits use fast progress rather than TQDM, by the way. That's what I hear. 00:34:37.020 |
>> So, here it's detected that -- you can see from the logging, which is noisy right 00:34:41.820 |
now. It detects that the dependency block implies script will only need VM and pip. 00:34:47.740 |
So, you don't need to have conda on your system to use it. That's the other reason I wanted 00:34:50.660 |
to make it so it didn't require conda. The whole point of this is to create a thing where 00:34:55.100 |
people need to install the minimum amount in order to be able to use scripts. So, it 00:35:01.300 |
needs to create the VM and then it does that. And then within it, it installs this library. 00:35:07.060 |
And if we go look at the cache directory, which, again, needs renaming, we'll see there's 00:35:11.060 |
a new entry. There. This one, hopefully, just has the requirements.txt file properly formatted 00:35:18.060 |
in the VM inside there. So, that's the gist of it. It's a little noisy right now. It doesn't 00:35:25.820 |
do all the error checking, right? >> I like it. And, like, with -- people don't 00:35:32.660 |
quite realize on the whole, I think, that conda has, like, every program you could imagine, 00:35:42.060 |
>> GraphViz, Node, whatever. So, if you wanted to have a script that creates database diagrams, 00:35:53.820 |
you know, and send it to somebody using the thing I showed yesterday, you could have this 00:35:58.420 |
and it would have a, you know, conda install. >> Yes. 00:36:01.740 |
>> GraphViz there. >> It's very general. And there's a couple 00:36:05.780 |
-- well, like, a little bit of context on this. Like, part of the reason I'm so militant, 00:36:11.540 |
I guess, about, like, easy deployment in single files is that I've -- in the past operating 00:36:17.220 |
environments where not everyone around me was a software engineer, at my -- where I 00:36:20.980 |
was CTOing at my startup, we'd have a factory, like, a literal physical factory that was, 00:36:25.700 |
like, right there as part of the office. And there would be technicians working with manufacturing 00:36:30.500 |
equipment. And we created software just for them to use. 00:36:32.380 |
>> That's, like, what you guys were making. >> Oh, yeah. We were making -- right. Making 00:36:36.620 |
custom eyeglasses. And so, we had -- we used machine learning to scan the face. 00:36:42.620 |
>> Like, per person customized, right? >> Per person. So, we scan your face with the 00:36:47.540 |
front-facing iPhone camera, eventually the depth sensor, do inference to work out the 00:36:52.900 |
3D shape of the face. And those measurements of the shape of the face would get fed into 00:36:57.340 |
computer-controlled milling machines, CNC machines, to make the glasses that exactly 00:37:02.420 |
fit your face. And so, as part of the business operations, it wasn't just people doing ML, 00:37:06.920 |
people doing iOS development. There were people there operating CNC machines and making glasses. 00:37:12.620 |
And they would need to -- we needed to have a workflow so that they would get data that 00:37:17.180 |
came out of this -- came out of our database properly and was fed then correctly into the 00:37:21.340 |
CNC machines. You've got to do order tracking, customer tracking, taking payments, like, 00:37:26.420 |
all that stuff. So, you need a lot of bits and pieces of custom software that everyone 00:37:30.740 |
can use. The customer service reps, the factory technicians, the software engineers, the marketing 00:37:36.220 |
professionals. Like, all these people are super capable, but they're not all people 00:37:40.660 |
who want to know what the hell it even means to talk about, like, why are you bringing 00:37:44.260 |
a snake onto my computer, you know? Python this. It's ridiculous. Oh, what? I need to 00:37:49.220 |
install Swift first? What's Swift? Is that a bird? Like, you know, it's no good. Like, 00:37:53.220 |
you just want to be able to give them a goddamn file and then have them run it. And any time 00:37:58.580 |
you need to do anything else, like, oh, just, you know, update your node, like, you failed. 00:38:02.540 |
Like, the whole stack has failed. If you're requiring that, you've already lost. So, before 00:38:08.900 |
I, you know, want to make anything, I want to think about, is it going to be a thing 00:38:12.540 |
that someone else can use easily? Not, like, that they can use if they care about it. And 00:38:19.740 |
I couldn't do that with Python. And I could sort of barely do that with Swift, using the 00:38:22.820 |
Swift shell, you know, getup. But what I like about this is, you know, when I was talking 00:38:29.500 |
to you about this earlier, John, you were saying, well, this is good, but can you just 00:38:32.380 |
make it a Python module? Like, that might be good for Python users, but then it's chicken 00:38:37.220 |
and egg, because now they need to know how to install a Python module, right? Or they've 00:38:40.180 |
got to pip install the thing that saves them from doing pip installs. Right now, my goal 00:38:45.180 |
is for this thing just to be a single file that anyone can put in their path, if you 00:38:49.020 |
could explain to them where a path is, and then if they do that, and then you can also 00:38:53.300 |
explain the shebang. So, we're already deeper in than we want. 00:38:55.740 |
>> So, Alexis, I have, I have things that might be helpful to you. 00:38:59.940 |
>> Yes, yes. I'm interested, I have a bunch of questions, but I'd be interested in feedback, 00:39:03.140 |
thoughts. >> I have a, I have a installer for Miniconda 00:39:10.780 |
that you can just run, and it works, it'll install, and without any interactive anything, 00:39:17.060 |
it'll Miniconda on Windows, Mac, and Linux. And I believe somewhere I also have that sitting 00:39:25.900 |
on a, like, a URL, so you can just curl blah, pipe, bash, and you don't even have to download 00:39:35.740 |
it. So, yeah, if you want to be like, okay, to run this script, you'll need Miniconda. 00:39:42.540 |
If you're not sure if you've got that, or you know that you don't, copy and paste this 00:39:45.900 |
one line, and you're done. >> Yeah, that's a good, that'd be very interesting, 00:39:53.500 |
because I think I want to, I haven't, obviously, it's a bit of a mess right now, because I 00:39:57.140 |
just got it working, but my goal is to make it extremely easy to adopt, so that, like, 00:40:05.300 |
data scientists and people who are smart and have a need to, like, maybe do a little bit 00:40:10.020 |
of scripting, can use, really, all of Python, without needing to learn the package. 00:40:16.540 |
>> Exactly. Also, remember that you can pip install from a git repo directly. Things don't 00:40:24.780 |
have to be on PyPy. So, two things. A, make sure your regular expression handles plus, 00:40:32.380 |
because that's what you, you'll be git plus, blah, blah, blah. The second would be, you 00:40:37.580 |
might want to, like, mention it, if you've got some kind of tutorial, or readme, or something, 00:40:42.140 |
is, like, here's the absolute easiest way to create a package for somebody else to use. 00:40:48.860 |
And nowadays, with pyproject.toml, that's, yeah, pretty easy. So, if you've got a repo 00:40:55.140 |
with a pyproject.toml in it, you've now got something that people can pip install, which 00:40:59.340 |
means you've now got something that people, so, for people who are slightly more advanced, 00:41:04.620 |
they can create things to enhance other people's Python scripts. 00:41:11.100 |
>> So this was the part where I was interested in getting feedback from both of you, because 00:41:16.460 |
I feel like there's a lot of, there's some design choices to be made here that are shallow 00:41:21.420 |
in engineering terms, but very consequential in user experience terms. And those are the 00:41:28.220 |
design choices around what format to require/accept in this comment block. 00:41:34.780 |
>> Yeah, I mean, don't, that's too complicated. Like, requirements.txt is fine. Pyproject.toml 00:41:41.220 |
would be if you, you know, wanted to create a package for somebody else to install. 00:41:46.140 |
>> Yeah, so I was experimenting with this, but then I rejected it, because when I started 00:41:50.300 |
looking at what constitutes the simplest, the kind of minimum parsable, pyproject.toml, 00:41:58.180 |
it was already longer than it needed to be. >> Yeah, yeah, and it's not, like, it doesn't 00:42:04.780 |
>> The other thing I'd say is, for your examples, like, I don't know, I discourage people from 00:42:15.460 |
putting specific version numbers in, in their requirements.txt. I'd say this for here as 00:42:23.460 |
well, you know, I'd probably just say greater than or equal to four, less than five, or 00:42:34.220 |
>> There's a tendency, I mean, thusly, this comes very much from the, from the NPM world 00:42:38.660 |
where, where everybody has these lock files and stuff. So people in the Python world tend 00:42:44.700 |
to use this equals equals thing, but I think it's not, I mean, it doesn't matter so much 00:42:50.540 |
what you're doing, because everything's going to be in a separate env anyway. 00:42:53.340 |
>> Yeah. >> But I kind of discourage people from thinking 00:42:56.780 |
this is how we should package software, that it depends on the specific sub sub version 00:43:01.740 |
of a package, you know. >> Well, why? Why do you say that? Let me, 00:43:07.140 |
let me disagree a little bit, or at least check out where you're coming from. 00:43:08.980 |
>> Yeah, no, it's fine. Like I say, in your particular case, it actually doesn't matter 00:43:11.860 |
too much, because you're going to have, well, the only reason why is that if I've got a 00:43:17.820 |
different pack, a different script that uses 4.66.5, it's going to have to download a separate 00:43:23.420 |
one and store the separate one in my packages, and I can't hard link anymore. And so all 00:43:27.340 |
those things I'm saying about how efficient and fast and low disk usage this will be, 00:43:31.700 |
would be thrown away, thrown out. >> Well, they'd be compromised somewhat, because 00:43:36.460 |
>> On the system, yeah. >> And you're not winning anything. And it's 00:43:39.580 |
kind of, for people who are, you know, more beginner-y, just learning-y types, it's kind 00:43:46.220 |
of saying to them, like, oh, this is how you're meant to package software. It has, you know, 00:43:49.860 |
you're meant to assume that it only works in the specific sub sub version. That's a 00:43:54.860 |
minor issue, but. >> I think it depends on the sophistication 00:43:58.500 |
of the consumer. So if I, like, think back to my, like, prototypical use scenario, if 00:44:03.140 |
I want to hand someone a script that they can run, even if they have less, you know, 00:44:08.380 |
technical expertise around Python, I really want to do everything I can to make sure that 00:44:12.180 |
it will run, like, no matter where it lands. Like, if it's raining, if it's snowing, if 00:44:18.700 |
they're running Python 3.10, if they're running Python 3.7. 00:44:21.180 |
>> No, no, absolutely. I agree. >> I want it just to work. So locking that 00:44:24.100 |
down, because if I make it open-ended, then I face the risk that at some point there will 00:44:28.220 |
be a future release. >> Well, that's what I'm saying. You don't 00:44:30.580 |
make it open-ended. You make it slightly more open-ended, right? So for mine, I generally 00:44:34.780 |
write greater than or equal to x, where x is the minimum version I know works, and then 00:44:39.940 |
less than, and then I write the next major version number. 00:44:43.100 |
>> Okay. >> Or, you know, you can make it slightly 00:44:47.180 |
less annoying. Like, you could just write 4.66.star, you know, or 4.66, I think, might 00:44:53.100 |
work. >> So pin major and minor version. I can see 00:44:57.220 |
that. >> Anyway, it's a minor issue. I also noticed 00:45:00.500 |
in your actual script, I think your regular expressions could be less strict. So I would 00:45:09.540 |
use hash backslash s star in the conda header and pip header, rather than hash space. I 00:45:19.500 |
would also put a backslash s star after the colon. 00:45:22.420 |
>> Sorry, which line are you talking about? >> So, yeah, those two lines, 23 and 24. After 00:45:26.940 |
the hash, I would change the space to backslash s star. 00:45:32.180 |
>> Oh, so it could be an arbitrary number of whitespace tokens? 00:45:37.140 |
>> Yeah, and I would also put arbitrary amount of whitespace before the new line. 00:45:41.620 |
>> Yeah, I know, that's all. >> And rather than using a new line, I would 00:45:47.620 |
put an R before that string, so that you then don't need new line. Instead, I'd say dollar, 00:45:53.460 |
and then, well, it depends how you're doing this exactly, but I don't know. That backslash 00:45:58.060 |
s, in some versions of Python, that might now complain that you haven't, this is not 00:46:10.120 |
>> That should be backslash s star, not backslash s plus. You don't want to require spaces before 00:46:16.220 |
your new line. >> I do, though, because I want everything 00:46:17.780 |
to be hash and then a space, at least one space at the beginning. 00:46:20.980 |
>> Yeah, but not at the end. >> That's true, yeah, yeah, yeah, okay, yeah, 00:46:25.500 |
you're right. >> And then pipheader probably wants a plus 00:46:30.780 |
as well. >> Yeah, what I'm curious about is why I picked 00:46:36.660 |
up the pip block at all when, earlier, so there's probably a deeper problem here I haven't 00:46:43.500 |
sorted out. >> People don't have to watch this, watch this 00:46:46.740 |
debug together, but, yeah. It's more of a general comment. It's in general for these 00:46:51.540 |
kinds of things. I try to make my matching things reasonably flexible. 00:46:59.820 |
>> So this goes to the other thing I was wondering about. So I think it's almost certainly the 00:47:04.820 |
right decision to use a syntax where, first of all, instead of putting things off of the 00:47:13.060 |
comments line here, off of, you know, next to the thing, actually just have a block at 00:47:17.100 |
the top. Because that means that the requirement, yeah, because that means in particular. 00:47:21.300 |
>> But I would put them in, this is quite a common pattern nowadays, is to put things 00:47:27.180 |
in a YAML fenced block, so that would be, except commented, so that would be a hash 00:47:34.180 |
space dash dash dash at the top and a hash space dash dash dash at the bottom. And that 00:47:39.580 |
way it's like very clear exactly where your block starts and stops. And if there's anything 00:47:44.820 |
in there which you don't recognize in the block, you can tell people, you know, rather 00:47:48.540 |
than it just mysteriously not running that thing. It's a YAML metadata block. It's just 00:47:58.540 |
dash dash dash followed by some lines. And at the end it's another dash dash dash. 00:48:05.540 |
>> But I'm going to have to put hashes around it. 00:48:11.620 |
>> You're going to hash before it, yeah. And with, you know, as many spaces as you like. 00:48:15.860 |
>> So the thing that was -- I want to follow up on that because I'm not 100% sure I understood. 00:48:23.180 |
But the one particular thing that I really wanted to get both of your opinion on is what's 00:48:29.900 |
>> Yeah, that's the next thing I want to mention. So I think you should have two separate sections. 00:48:36.460 |
I think you should have a conda requirements. And conda requirements would all get passed 00:48:43.860 |
to a single conda install minus YQ. And then the entire lot of requirements space delimited 00:48:49.660 |
would all get done at once. Because most people don't need conda commands. And that's not 00:48:56.740 |
really a conda command source. It's just a, you know, commands source. You know, it's 00:49:04.540 |
>> So I started looking at conda requirements. But as near as I could tell, there wasn't 00:49:07.700 |
a well-defined format that was specified by conda that had all the properties -- 00:49:17.340 |
>> There is. It's the thing you've got there. It's the thing you've got there, which is 00:49:19.660 |
the thing that appears after the minus minus quiet. So that's what we use in nbdev as well. 00:49:26.700 |
I would restrict exactly like your requirements.txt, but I would have, you know, conda requirements. 00:49:32.740 |
>> Right. So the reason I thought that might not work -- and you can correct me on this, 00:49:37.460 |
because you know a lot more than I do -- is that if you happen to be installing something 00:49:42.540 |
where you wanted to rely on different channels for different packages, then the binding through 00:49:51.700 |
which this channel applies for these packages and that channel applies for those packages 00:50:01.420 |
>> And, you know, I would be inclined to have like in the, like, conda requirements, you 00:50:08.220 |
know, space channels colon. And that way you've got like -- you know, because it's very rare 00:50:15.180 |
that you need to like almost -- I don't think I've ever needed to specify different channels 00:50:18.700 |
for different things. I just have channels for everything. So I would have, like, hash 00:50:24.940 |
conda requirements space conda-forge space fast-chan colon, you know, and then I'd have 00:50:30.900 |
just my requirements one per line. And if you did need a specific channel for a specific 00:50:38.580 |
thing, you can just use -- like, and if all you're doing is just concatenating with a 00:50:42.340 |
space, then it'll work, because you can, you know, a user can put channel colon. 00:50:45.980 |
>> Okay. I think I need to see that syntax to understand it. You say it's using nbdev 00:50:54.300 |
>> There's no syntax. What you've got, Python equals 3.10. That's the syntax. NumPy, that's 00:51:02.700 |
>> Yeah, that's what I say. You'll never -- like, I've never used it in my life. So I just like 00:51:08.020 |
-- A, you don't have to worry about it. B, you don't have to do anything to support it. 00:51:12.620 |
Because it'll just happen. If you just pass it along to conda install, it'll just work. 00:51:22.540 |
So I guess I'm thinking about setups like this. So -- 00:51:27.020 |
>> So you just dump it. It's fine. You just dump them all, like, in one command. It'll 00:51:34.180 |
>> So there's not a complicated binding that needs to be maintained here between cuda is 00:51:39.380 |
enabled by this channel, this stuff is enabled by the PyTorch channel, the NVIDIA channel. 00:51:44.620 |
>> These things are coming out of the default. And if I don't preserve that binding property, 00:51:48.500 |
then the installation won't work, if I do it on one line? 00:51:51.060 |
>> I mean, it would -- it's unusual for that to be the case. And if it is, then people 00:51:58.260 |
can put it in the commands one, you know? But I would -- I suggest that for the normal, 00:52:04.820 |
easy stuff that's, like, 99.999% of the time, just -- 00:52:09.300 |
>> Okay. Yeah. Yeah. Because I was trying to find an easy format to use that was also 00:52:17.260 |
well-specified and natural. And I wasn't sure what there was. It sounds like what you're 00:52:20.780 |
saying works. What I liked about this was -- what I didn't like about this was it wasn't 00:52:25.100 |
a well-specified format. It was just the commands people would issue. But then what I sort of 00:52:28.700 |
liked about it is, it was just the commands people would issue. So if you can imagine 00:52:31.820 |
there's somebody who doesn't know their way around, but has made these commands before, 00:52:36.220 |
it's not too frightening to see, oh, okay, these commands will be run. 00:52:39.500 |
>> No, exactly. I just support both. But for the one you've got here, there's no reason 00:52:43.980 |
it couldn't say conda, colon, Python equals 3.10, numpy. 00:52:51.660 |
>> Yeah. So basically something like -- this is what you're suggesting? 00:53:05.420 |
>> Yeah. I mean, I wouldn't put the .txt there, because it's kind of weird, but, yeah. 00:53:09.980 |
>> Okay. And then the -- well, I'll look up what you mean by the YAML fencing. You mean? 00:53:16.780 |
>> So I would -- yeah, but I would have run the whole thing, not just for the conda bit. 00:53:20.780 |
Three dashes, not four. No, not there. So I would go right to the very -- to line two. 00:53:27.580 |
I would insert a new line in line two. And I would put hash dash dash dash there. And 00:53:36.220 |
then I would go to line 10 and put a new line after that and put another hash dash. 00:53:39.820 |
>> Oh, I see. To fence the whole thing, not the separate parts. 00:53:42.700 |
>> Yep. And then you just grab it. And then if somebody's accidentally typed the wrong 00:53:47.020 |
thing somewhere, you can say, like, I didn't understand that line, you know? 00:53:53.660 |
any requirements of any kind, you can say, like, oh, you've got a fence block, but there's 00:53:57.260 |
nothing I recognize at all, or -- et cetera. >> Yeah. Yeah, that might be good. I'm just 00:54:04.620 |
trying to think about how to make it easy for someone who's never -- doesn't really 00:54:07.500 |
know what a shebang is, doesn't quite know what conda is, but they kind of know, you 00:54:11.340 |
know, I found a thing and now I'm trying to modify it to get a new result out of it, which 00:54:14.380 |
is a likely situation for -- >> Yeah, exactly. 00:54:17.420 |
>> -- certain classes. >> I think this is fair enough, 00:54:19.180 |
what you have to edit. >> But I'm very excited by it. I know 00:54:23.820 |
it's a tiny little thing. It's less than, you know, less than 300 lines of code or whatever. 00:54:27.020 |
But I think it will enable it to be easier to experiment with stuff. Just create a single 00:54:31.820 |
file, run it, get on with your day. >> I don't remember the last time I 00:54:37.500 |
wrote something with over 300 lines of code in it, so I wouldn't measure things based 00:54:41.420 |
on how many lines of code it has. >> Yeah, I mean, that's a figure of 00:54:44.700 |
merit. I'm just saying it's not a -- yeah, it's not a big thing. It's just a little thing. 00:54:48.860 |
Oh, the other question is where to dump all the garbage. 00:54:51.340 |
>> Yeah, XTG is the right thing to do, exactly. >> If it exists, but if it doesn't, then, 00:54:57.340 |
I don't know, is it going to .cache on Linux and library developer on Mac OS? 00:55:01.420 |
>> Yeah, I'm trying to remember. I think FastCore, let me check. 00:55:15.260 |
>> I just copied this behavior from SwiftShell because Max usually makes good choices. 00:55:23.740 |
>> Yeah, so there's a FastCore.xtg library, which you could borrow. Yeah, and it attempts to 00:55:34.380 |
have something sensible for everything, although it could probably be improved because 00:55:40.220 |
it -- yeah, it's -- I mean, I don't know if it's wrong, but it's, you know, if you don't have 00:55:49.500 |
something, like if you don't have XTG cache home, it uses path.home/.cache, for example. 00:55:56.780 |
>> What file is that, Defender? >> FastCore/xtg.py. 00:56:15.460 |
Okay, well, definitely something -- >> So if you feel like there are things, 00:56:28.780 |
better places to put things on Mac, I would rather a PR to this than -- 00:56:38.100 |
Yeah, I'll give it a think. Apple often has pretty good docs if you look for them about where things 00:56:45.660 |
>> How fully -- >> Yeah, I think I really only 00:56:48.860 |
looked up the Linux or POSIX or something docs. I didn't really think about Mac specific. 00:56:55.740 |
Nice, Alexis. Thank you. >> Yeah, my pleasure. 00:57:03.500 |
It's nice to get excited about a little thing, because, you know, it'll be done quickly because 00:57:07.100 |
it's little, and then, you know, you can actually then go on and use it and get on something else. 00:57:10.300 |
>> Yeah. Maybe this is why I only ever do little things. But the nice thing is, like, if you kind 00:57:17.660 |
of organize your little things in a nice way, eventually you discover that they all created 00:57:26.060 |
>> Nice. All right. We done? We good? >> I think we're good.