Python Scripts in Virtual Environments in Background macOS

Hello all.


I have successfully driven myself nuts with this. Title says what I'm trying to accomplish. Using 2 services - 1. wiki Drazzilb08/daps and 2. local Kometa.


These install pretty similarly and are invoked similarly but I can't seem to blend them together. I have tried too many things to enumerate here but they include: running the python command with nohup, running with disown, making a LaunchAgent plist that calls a sh script to run the commands, all to no avail. I have tried specifically also to adapt the Kometa plist to the daps but I don't understand what this one does so...

The plist I'm trying to understand

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>Label</key>
 <string>com.YOUR_USERNAME.kometa</string>
 <key>ProgramArguments</key>
 <array>
     <string>sh</string>
     <string>-c</string>
     <string>kometa-venv/bin/python kometa.py --config /path/to/kometa-config/config.yml</string>
 </array>
 <key>UserName</key>
 <string>YOUR_USERNAME</string>
 <key>WorkingDirectory</key>
 <string>/PATH/TO/KOMETA</string>
</dict>
</plist>

Which gets invoked peculiarly to me

cd ~/Library/LaunchAgents/
launchctl bootstrap gui/YOUR-USER-ID com.YOUR_USERNAME.kometa.plist

And doesn't seem to work. How can I best accomplish 2 python scripts in background in their respective virtual environments at startup running macOS 14.7.2


I'd appreciate any advice!

Mac mini, macOS 14.7

Posted on Jan 18, 2025 11:31 AM

Reply
Question marked as Top-ranking reply

Posted on Jan 18, 2025 5:56 PM

rothnd wrote:

So I have a group of scripts run by the main.py script of daps. Right now my problem is with using a plist to load main.py so it's always running/accessible and so that it has access to an rclone exec.

What is all of that? What is daps? What is rclone?


What do you mean by "accessible"? You can run some script, that's fine. But is said script providing some kind of service? What is "accessing" it? And how?


Is rclone this thing? https://github.com/rclone/rclone "rsync for cloud storage" - because rsync is just a pleasure to use elsewhere. </sarcasm>

I invoke the main.py manually with
cd /Users/nathan/daps
source .venv/bin/activate
python3 /Users/nathan/daps/main.py

OK. Now we're getting somewhere.

which seems to work fine. However, when I attempt to load main.py in the background and it makes its call to rclone, rclone fails (command not found).

So this daps thingy is supposed to call some other open-source thingy to do something with some 3rd party cloud service? If you ever get this running, maybe wrap it all up into an app and sell it as "Masochist Cloud - the media manager choice for people who want to punish themselves."

My updated plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.nathan.daps</string>
<key>ProgramArguments</key>
<array>
<string>sh</string>
<string>-c</string>
<string>.venv/bin/python3 main.py</string>
</array>
<key>WorkingDirectory</key>
<string>/Applications/daps</string>
</dict>
</plist>

That's never going to work.


You have to go back your manual execution and figure out what that's doing.


cd /Users/nathan/daps

Change the working directory to the daps directory in your home directory. OK. Fair enough.


source .venv/bin/activate

This is more complicated. It's going to stuff a bunch of stuff into your environment. What kind of stuff?


python3 /Users/nathan/daps/main.py

Run python3 (presumably found in some path stuffed in via step 2) and execute this python script.


That's 3 steps. You can't do that in a launchd script. You could kinda do #1 via WorkingDirectory, but that's such a cop-out. But regardless, you can't do those other 2 steps. I don't know. Maybe you do something funky with "sh" and semicolons. How about we do it properly instead?


What you have to do is merge these into a single script. The script is pretty simple. First it changes to the desired directory. Then it runs "source .venv/bin/activate" and then it runs "python3 /Users/nathan/daps/main.py". Save the three-line script as something named "daps.sh" in some convenient place. Probably shouldn't put it in the existing "daps" directory though.


If you want to be really fancy, you could add a shebang line and make the script executable with "chmod". Then you could just run the script with nothing else. Otherwise, you'll still have to run "sh" to execute it. Since it's a stand-alone script, you don't need the "-c" parameter.


Your plist would look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>Label</key>
 <string>me.nathan.daps</string>
 <key>ProgramArguments</key>
 <array>
     <string>/bin/sh</string>
     <string>/Users/nathan/bin/daps.sh</string>
 </array>
</dict>
</plist>



12 replies
Question marked as Top-ranking reply

Jan 18, 2025 5:56 PM in response to rothnd

rothnd wrote:

So I have a group of scripts run by the main.py script of daps. Right now my problem is with using a plist to load main.py so it's always running/accessible and so that it has access to an rclone exec.

What is all of that? What is daps? What is rclone?


What do you mean by "accessible"? You can run some script, that's fine. But is said script providing some kind of service? What is "accessing" it? And how?


Is rclone this thing? https://github.com/rclone/rclone "rsync for cloud storage" - because rsync is just a pleasure to use elsewhere. </sarcasm>

I invoke the main.py manually with
cd /Users/nathan/daps
source .venv/bin/activate
python3 /Users/nathan/daps/main.py

OK. Now we're getting somewhere.

which seems to work fine. However, when I attempt to load main.py in the background and it makes its call to rclone, rclone fails (command not found).

So this daps thingy is supposed to call some other open-source thingy to do something with some 3rd party cloud service? If you ever get this running, maybe wrap it all up into an app and sell it as "Masochist Cloud - the media manager choice for people who want to punish themselves."

My updated plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.nathan.daps</string>
<key>ProgramArguments</key>
<array>
<string>sh</string>
<string>-c</string>
<string>.venv/bin/python3 main.py</string>
</array>
<key>WorkingDirectory</key>
<string>/Applications/daps</string>
</dict>
</plist>

That's never going to work.


You have to go back your manual execution and figure out what that's doing.


cd /Users/nathan/daps

Change the working directory to the daps directory in your home directory. OK. Fair enough.


source .venv/bin/activate

This is more complicated. It's going to stuff a bunch of stuff into your environment. What kind of stuff?


python3 /Users/nathan/daps/main.py

Run python3 (presumably found in some path stuffed in via step 2) and execute this python script.


That's 3 steps. You can't do that in a launchd script. You could kinda do #1 via WorkingDirectory, but that's such a cop-out. But regardless, you can't do those other 2 steps. I don't know. Maybe you do something funky with "sh" and semicolons. How about we do it properly instead?


What you have to do is merge these into a single script. The script is pretty simple. First it changes to the desired directory. Then it runs "source .venv/bin/activate" and then it runs "python3 /Users/nathan/daps/main.py". Save the three-line script as something named "daps.sh" in some convenient place. Probably shouldn't put it in the existing "daps" directory though.


If you want to be really fancy, you could add a shebang line and make the script executable with "chmod". Then you could just run the script with nothing else. Otherwise, you'll still have to run "sh" to execute it. Since it's a stand-alone script, you don't need the "-c" parameter.


Your plist would look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>Label</key>
 <string>me.nathan.daps</string>
 <key>ProgramArguments</key>
 <array>
     <string>/bin/sh</string>
     <string>/Users/nathan/bin/daps.sh</string>
 </array>
</dict>
</plist>



Feb 6, 2025 11:50 AM in response to rothnd

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>

<key>Label</key>

<string>com.nathan.dapsmain</string>

<key>ProgramArguments</key>

<array>

<string>/Users/nathan/daps_other/myscripts/other/dapsmain.sh</string>

</array>

<key>RunAtLoad</key>

<true/>

<key>KeepAlive</key>

<true/>

<key>StandardErrorPath</key>

<string>/tmp/stdout.log</string>

<key>StandardOutPath</key>

<string>/tmp/stderr.log</string>

</dict>

</plist>

Which calls my script 'dapsmain' which is

#!/bin/bash


cd /Users/nathan/daps/

source .venv/bin/activate

python3 /Users/nathan/daps/main.py

deactivate

This gets into the whole virtual environment for python script thing previously discussed. Just to make sure/try here I believe you said it doesn't need to be manually 'deactivated' in these cases, it's only needed when invoking manually in Terminal correct? If so, I suppose I should remove this deactivate from my sh script? Going back to the Bazarr example above, I'm wondering again why the Automator run shell login item?


Kometa - rather than further elongating this now I'd just like to say here Kometa is similar to DAPS in invocation but without the internal scheduling detailed above. So, when I want to run Kometa on schedule I have a launchd plist similar to the DAPS one above but with a CalendarInterval for each call to each function e.g.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>

<key>Label</key>

<string>com.nathan.kometa</string>

<key>ProgramArguments</key>

<array>

<string>/Users/nathan/daps_other/myscripts/other/kr.sh</string>

</array>

<key>RunAtLoad</key>

<false/>

<key>StartCalendarInterval</key>

<array>

<dict>

<key>Hour</key>

<integer>17</integer>

<key>Minute</key>

<integer>0</integer>

</dict>

</array>

<key>StandardErrorPath</key>

<string>/tmp/stdout.log</string>

<key>StandardOutPath</key>

<string>/tmp/stderr.log</string>

</dict>

</plist>


But with Kometa I want to run say 3 different functions at 6 different times so I've found that I need 3 different launchd plists with their respective times? And the kr.sh script is very similar

#!/bin/bash


cd /Users/nathan/Kometa/

source kometa-venv/bin/activate

python /Users/nathan/Kometa/kometa.py -r

deactivate


I know this is extra long but I've been reading/experimenting for a while now and it just feels like I need to bounce these specifics off of someone who can help me focus learn to be able to apply things more generally later. Thanks for reading!



Jan 19, 2025 10:10 AM in response to rothnd

rothnd wrote:

If you look at that first kometa plist I posted. That's what's not working for me at the moment.

Of course not. As I said, it was always wrong. It would never have worked.

Both of these scripts have 'schedulers' so in theory the script is always running (start, login, etc) so that when the bell tolls it does its thing. I've been sorely confused on scheduling since I was just starting to use cron like last year

I'm not sure what you mean by "scheduler" in this context. It's simply too general of a word. But it definitely sounds like you are talking about two completely different and unrelated types of "schedulers".


If these Python scripts need to be always running, then cron is not appropriate. They should be launched at system start time instead. System start time typically involves system facilities, the root user, or, even better, an unprivileged, dedicated user. But these are advanced topics to it's better to start with a task that runs when a user beings a login session. Once you have that part working a normal user context, then you could move it if you wanted to.


The cron architecture is designed to run scripts on your local machine according to a given schedule. Maybe you want to run something every day at midnight, the 4th Thursday of each month, or every 17 seconds.

then it recently stopped working

Why is that? That's a rhetorical question, of course. What I mean is that you've technically over-extended yourself. There is a fancy term for it called "technical debt". Just like financial debt, the only solution is to pay it off. You can't fix it with additional debt.

these people routinely do stuff like that for tutorials and I'm left trying to decipher.

Don't bother. The internet is fake. They're simply lying to you. This was something you could have done a few years ago. But these days, it isn't possible. There is some legitimate content available, but only those who already know these technical details can identify what is fake and what is legitimate. And most of those people could probably do the given task themselves. It's a tricky thing, navigating disinformation in the modern world.

Basically, these 'projects' get confined to their own directories. I point Terminal at that directory. Create a python virtual environment for isolation. And run the scripts. One problem I'm having is in these virtual environments. source activate...do stuff....deactivate. But when I'm 'activated' in a Terminal session the Terminal won't release until deactivate. I'm trying to reconcile this 'release/deactivate' with a script running on a schedule needing to be 'always available'.

The confusion and misinformation builds upon each other.


The first thing to understand is that Terminal really has nothing to do with scripting. Terminal is an interactive command line environment. Scripting is a non-interactive environment. Probably their only real similarity with each other is that they both facilitate command-line program execution with arguments, as opposed to double-clicking an object in the Finder. Other than that one specific aspect, the only commonality they share is social - a community of practice. People who use one, tend to also use the other.


There is never any need to "deactivate" anything. That's simply an artifact of the "source" command when run in Terminal. It's normal for a script or executable to require very specific environment settings like PATH, etc. Normally a script would setup what it needs, and then run the desired command. When the command completes, the entire modified environment goes away. There's no need for it anymore.

But I would like to learn.

That's good then. Just remember that not everyone is honest. And dishonesty thrives on the internet. There are no laws, so anything goes. Now, with modern AI systems, they can generate these fake tutorials in seconds. They look correct. In many cases they may be 90% correct. But you can only learn by doing yourself.


Ideally, a structured, human-led, interactive, learn-by-doing practice is best. The material is structured so that it is always just a little bit more difficult than you can handle. That way, you don't get lost and you don't get bored. Back in my day, we used to call these things schools, colleges, and universities.


...to be continued...

Jan 19, 2025 1:11 PM in response to etresoft

So without getting too far off base here, I just want to get an opinion on what I'm currently testing while I come back to read the rest of these posts.


I decided to try the executable shell script method with screen to detach from terminal as in

#!/bin/bash

cd /Users/nathan/daps/
screen -S daps .venv/bin/python3 main.py

I chmod +x 'd it. Executed it. Added to Login Items. No launchd necessary that I can see..? main.py has an 'internal schedule' so user can set task 1,2,3....n at different times. The key for this is that main.py must be 'always on' like I was trying to explain.


How's that strike you?

Jan 19, 2025 10:18 AM in response to rothnd

Sorry, 5000 character limit per post.


rothnd wrote:

Specifically, you were saying something about just an executable script for this. So in plain terms, create exec script to run these virtual environments, add to login items (I'm assuming. No need for launchd?). How then do I handle the whole Terminal won't release (or needs to always have the window open) until deactivate?

As before, the problem is social, not technical.


Traditionally, the Mac community of practice involved running apps by double-clicking them. Login Items are apps that will run automatically at login without having to be manually double-clicked.


The Unix community of practice involved writing scripts, setting up environments, and running those scrips as cron jobs and/or system services.


When Apple made Mac OS X 25 years ago, they threw these two communities into the same box and they've been fighting ever since. It is possible to create wrapper apps that run command-line tools. It's also possible to create purely Mac-style (now iOS-style) scripts using AppleScript, Automator, and now Shortcuts. But usually, that's extra work. You have to get the command-line version working first. And in this case, wrapping it into a Login Item-friendly app probably isn't going to do anything for you.


However, I don't really know what to tell you at this point. My post the other day explained everything you needed to do. Create a single script that sets up your environment and then executes your task. You can test that in Terminal. But it has to be a one-liner. You can wrap it via "/bin/sh -c" or you can use "chmod" and shebang to make your script behave like a stand along executable. Either way is fine. But that one-liner can then be run via launchd.

Jan 18, 2025 12:13 PM in response to rothnd

rothnd wrote:

Title says what I'm trying to accomplish.

It does not.

Using 2 services - 1. wiki Drazzilb08/daps and 2. local Kometa.

I went to both site and I still have no idea what these things do.

These install pretty similarly and are invoked similarly but I can't seem to blend them together.

Blend them together in what way? What do they do?

I have tried too many things to enumerate here but they include: running the python command with nohup, running with disown, making a LaunchAgent plist that calls a sh script to run the commands, all to no avail.

The first step is always getting something running properly in an interactive Terminal session. Any kind of background operation is going to be wildly different. But that doesn't change the fact that you have to be able to run it manually first. Until you can do that, you will never make any further progress.


Assuming you can run them manually, please describe how you would do that, and what that would do for you.

I don't understand what this one does so...

Tell me about it.


The plist I'm trying to understand
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.YOUR_USERNAME.kometa</string>
<key>ProgramArguments</key>
<array>
<string>sh</string>
<string>-c</string>
<string>kometa-venv/bin/python kometa.py --config /path/to/kometa-config/config.yml</string>
</array>
<key>UserName</key>
<string>YOUR_USERNAME</string>
<key>WorkingDirectory</key>
<string>/PATH/TO/KOMETA</string>
</dict>
</plist>
Which gets invoked peculiarly to me
cd ~/Library/LaunchAgents/
launchctl bootstrap gui/YOUR-USER-ID com.YOUR_USERNAME.kometa.plist
And doesn't seem to work.

Of course not. It's wrong in at least 3 different ways.

How can I best accomplish 2 python scripts in background in their respective virtual environments at startup running macOS 14.7.2

At startup or login? Are these services used by a single user, or are they supposed to be available to all users?


What command lines would you execute if you just wanted to run it manually in Terminal?

Jan 18, 2025 1:27 PM in response to etresoft

Sorry I'm too confused myself. So I have a group of scripts run by the main.py script of daps. Right now my problem is with using a plist to load main.py so it's always running/accessible and so that it has access to an rclone exec.


I invoke the main.py manually with

cd /Users/nathan/daps
source .venv/bin/activate
python3 /Users/nathan/daps/main.py

which seems to work fine. However, when I attempt to load main.py in the background and it makes its call to rclone, rclone fails (command not found).


My updated plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>Label</key>
 <string>com.nathan.daps</string>
 <key>ProgramArguments</key>
 <array>
     <string>sh</string>
     <string>-c</string>
     <string>.venv/bin/python3 main.py</string>
 </array>
 <key>WorkingDirectory</key>
 <string>/Applications/daps</string>
</dict>
</plist>

Jan 19, 2025 8:16 AM in response to etresoft

Hey again. Been playing but needed a break from all this. Yes masochism at its best.


The simplified background. This is all for a personal media server, mostly cosmetic stuff we're talking about. DAPS does things like call rclone to sync contents of several people's google drives. Then several scripts to organize and manipulate that content to transfer it to the kometa app which is what applies all those manipulations to my media.


If you look at that first kometa plist I posted. That's what's not working for me at the moment. Both of these scripts have 'schedulers' so in theory the script is always running (start, login, etc) so that when the bell tolls it does its thing. I've been sorely confused on scheduling since I was just starting to use cron like last year and then it recently stopped working so trying to figure out this launchd. I understand what you mean about cramming several lines into one command of the plist but these people routinely do stuff like that for tutorials and I'm left trying to decipher.


Basically, these 'projects' get confined to their own directories. I point Terminal at that directory. Create a python virtual environment for isolation. And run the scripts. One problem I'm having is in these virtual environments. source activate...do stuff....deactivate. But when I'm 'activated' in a Terminal session the Terminal won't release until deactivate. I'm trying to reconcile this 'release/deactivate' with a script running on a schedule needing to be 'always available'.


I hope this clarifies a little more. Yes it's ridiculous. That I know. But I would like to learn. Specifically, you were saying something about just an executable script for this. So in plain terms, create exec script to run these virtual environments, add to login items (I'm assuming. No need for launchd?). How then do I handle the whole Terminal won't release (or needs to always have the window open) until deactivate?


Thank you!


[Edited by Moderator]

Jan 19, 2025 1:57 PM in response to rothnd

Is that daps program interactive? I have no idea if that will work. I've never heard of a command-line tool that runs as a service and is also interactive. Normally a service runs, in the background, without any interaction. If you do need interaction, there will be one or more client tools, or maybe even a web interface, to make any interactive adjustments.

Jan 19, 2025 3:36 PM in response to etresoft

I wouldn't say it's interactive, no. main.py is essentially a really long script comprised of a bunch of scripts with scheduling possibilities for each defined before any scripts. So the 'service' main.py needs to be running to compare the current time against the time stated in the schedule to 'do stuff'. Then if I want an unperiodic/manual run I invoke normally through Terminal.

Feb 6, 2025 11:48 AM in response to rothnd

Hello again. First let me apologize for not being more active here recently but if we can kind of pick up where we were I would very much like to try and enhance my understanding of/clarify some things in my quest to actually learn more about 'what this does'/'what I'm trying to do'. I'll also apologize for never having learned how to operate these forums (I click the quote button and all it does is jumble my text, not quote anything I'd like to quote, my problem entirely). I'll try with code insertions here but I can't figure out the quote thing.


Ok - so I have a situation (trying to work through more general/hypothetical with applications to the 'real-world version'. The situation let's say is I have 3 different python scripts written by third parties I would like to employ on my Mac, having them 'turn on' at startup and sit in the background and wait for additional commands. To clarify this, I'm trying to say "launch app A" at startup, and do nothing until further commands are received by/given to app A.

In this hypothetical I'm referring to the 3 python scripts Bazarr, DAPS, and Kometa. To me, all 3 should perform this way of launching at start and waiting for further at the very least.


I'll now try and illustrate how these 3 are launched/invoked/used.


Bazarr - this app has a (semi-usual) wiki on how to get it started with macOS. Specifically, here is the wiki page bazaar wiki detailing how to 'Autostart on macOS' according to this group/person. In essence, I create a launchd item with this plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.github.morpheus65535.bazarr</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/local/bin/python3.8</string>
      <string>/Applications/bazarr/bazarr.py</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardErrorPath</key>
    <string>/usr/local/var/log/bazarr.log</string>
    <key>StandardOutPath</key>
    <string>/usr/local/var/log/bazarr.log</string>
  </dict>
</plist> 

which to my understanding runs the bazarr python script by calling this script against the local python exec the instructions have users install (3.8), which is set to RunAtLoad (to me meaning at startup) and to KeepAlive (to me meaning be ready in background and await further commands. This seems ok generally to me but if you see something odd please tell! My question for this one is in the part of the instructions that instruct to create an Automator app to run shell script (loading the plist into launchd) to have something to put in login items...? This doesn't make sense to me. Isn't a launchd item set to RunAtLoad essentially a login item? Why do I need something to 'launch' a launchd property on start if this is how things are start are launched usually?


DAPS - this is basically one large (main) python script which calls a half dozen lesser python scripts with certain details/configuration settings (so they can distribute a suite of scripts that work by putting all personal configuration details into one script to edit). So in theory an either/or to me is: I have to create a launchd plist to call/run each of the lesser scripts in order to run them at scheduled times or I can create one launchd item to call/run the large (main) and keep it alive so that it can run individual scripts on their own individual schedule. I've been going with option 2 here i.e. one launchd item to get the main running at start and in background but I'm having trouble theoretically reconciling how this one is any different to the last one (Bazarr). Just trying to figure out/understand generally why 3 python scripts require 3 different launch methods (or so it seems)?

So for this one I have some scheduling info set in the main script and I launch this with a launchd plist of

-- character limited --

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

Python Scripts in Virtual Environments in Background macOS

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.