Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
i vomit kittens
Apr 25, 2019


In order to get your last code block to work, you would want to have push() raise an exception in the cases where it is not successful. This could be one of the predefined ones that you laid out in the second code block (IOError, OSError) or you can define your own if you're feeling saucy.

Take a look at 8.4 and 8.5 in the documentation here for instructions on how to do both of those things.

Adbot
ADBOT LOVES YOU

The March Hare
Oct 15, 2006

Je rêve d'un
Wayne's World 3
Buglord
Also worth looking at "finally" in python if you aren't familiar with it. Probably not useful for this situation, but useful for many.

YanniRotten
Apr 3, 2010

We're so pretty,
oh so pretty
If you don’t need any fancy error handling, running cleanup() directly after push() in the same block is an option, and you can structure push to not catch any critical errors that mean it failed. If push() fails by raising an exception, cleanup() won’t be executed.

Does that make sense? I feel like lots of people do too much exception management and swallow errors that should interrupt execution. There’s no functional reason to manage exceptions unless you have a recovery strategy. If an error isn’t recoverable (or not worth making deep changes to your program to recover) it’s reasonable to crash.

It’s possible there’s an understanding gap here about how exception handling works. If a statement inside of push() raises an exception, you don’t have to catch that with a try/except inside of push(). Exceptions bubble all the way up the stack until an enclosing try block handles it in some way or your entire program crashes.

YanniRotten fucked around with this message at 17:50 on Feb 18, 2020

fuf
Sep 12, 2004

haha

YanniRotten posted:

There’s no functional reason to manage exceptions unless you have a recovery strategy. If an error isn’t recoverable (or not worth making deep changes to your program to recover) it’s reasonable to crash.

This makes sense but I think in this case I need to actually catch the error because the script is going to run every hour or so and we'd want an email alert if it wasn't working... presumably that would be harder to do if the program just crashes.

YanniRotten posted:

It’s possible there’s an understanding gap here about how exception handling works. If a statement inside of push() raises an exception, you don’t have to catch that with a try/except inside of push(). Exceptions bubble all the way up the stack until an enclosing try block handles it in some way or your entire program crashes.

Yeah this makes me think I'm going about it the wrong way. I should maybe just put the whole script in one big try block that catches any exception? Then send an email alert with the exception.

For my own peace of mind I think I still need some kind of check that push() has done its job properly (maybe by counting the remote files before and after it's called and checking the right number have been uploaded), because if the "cleanup" process moves local files before they've been uploaded that would be pretty disastrous...

Thanks for the replies! Will keep working on it tomorrow. This is my first opportunity in this new job to do some actual coding so it's a nice change. :)

KICK BAMA KICK
Mar 2, 2009

fuf posted:

I should maybe just put the whole script in one big try block that catches any exception? Then send an email alert with the exception.
Look at sys.__excepthook__ I think it is if this is the strategy you want to take.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

If the script is being run with cron, cron will just email you the stderr when the script crashes.

(assuming your host system is configured correctly)

susan b buffering
Nov 14, 2016

yeah, you're gonna have a much better time keeping the script simple and letting an external runner send you an email when the script fails.

if anything, you may want to do some logging to help diagnose any issues that come up. if you use systemd timers instead of cron then logging is simply a matter of printing log events to stdout

Antigravitas
Dec 8, 2019

Die Rettung fuer die Landwirte:

fuf posted:

this is some real programming 101 poo poo and I'm embarrassed to ask but... what's the best way to check if a function has finished successfully before running a second function?

Several things:

One, you'd generally assume that everything is fine and continue the program with that assumption. Returning a bool for success/failure is something you do in languages that don't have exceptions, or if you want to do tests (e.g. if this_file_exists(): ). On failure you can let the exception thrown by functions bubble up or throw your own.

Second, if you need to do setup/cleanup you could consider writing a context handler instead, so you could do something like this (completely made up) example:
code:
with sftp_connection('localhost') as con:
    con.put(somefile)
Context handlers are really nice because you can bundle the setup/cleanup code and don't have to remember cleaning up.

Third, you could use the python built-in logging module. I use this a lot in scripts that run in cron. Catching an exception and exiting with a non-zero exit code after writing the exception message with logging.error() or logging.critical() is the most unix-y way of terminating after an unrecoverable error. Letting the exception bubble to the top prints a stack trace to stderr and that's often scary to people who get to see it.

Plasmafountain
Jun 17, 2008

ant73YBIrcjUaGP9z82f
tPaoT8BKnTOFItQt6iWW
sHjfi9IWi8r8W094AXUT
C9VLwa1fvajX1VJxLNpj
fUUWQJhZdyvyaetarV0U
VXgNjSCoh1Lp9puLTaKF
XYIflrfSmPTnBoVlSlNQ
OGN0KYE84Kl9axBZtJEL
8WmwGxwywN0mv56Fsjz0
BpkyVd8ivulI39aMew3W

Plasmafountain fucked around with this message at 23:58 on Feb 27, 2023

susan b buffering
Nov 14, 2016

You can use NetworkX to draw graphs with matplotlib, but the docs for this will tell you to use a dedicated tool like graphviz.

graphviz is a separate executable but the graphviz python module will call it for you to render graphs, so you don't need to feed it anything manually.

CarForumPoster
Jun 26, 2013

⚡POWER⚡

skull mask mcgee posted:

You can use NetworkX to draw graphs with matplotlib, but the docs for this will tell you to use a dedicated tool like graphviz.

graphviz is a separate executable but the graphviz python module will call it for you to render graphs, so you don't need to feed it anything manually.

Same suggestion adding maybe this might help: (uses graphviz)
https://github.com/fastai/fastdot

Antigravitas
Dec 8, 2019

Die Rettung fuer die Landwirte:

Zero Gravitas posted:

From what I can find I seem to be pushed towards Graphviz but from what I can see graphviz is installed as a seperate exe that then has prepared files fed into it.

Graphviz has this kind of thing figured out pretty well so there aren't many competing solutions. You can feed it from stdin though so there are a number of wrappers available. The file format is pretty simple and human-writable.

Also: Gravitas :respek: Gang

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
The impression I got from Zero Gravitas' post is they wanted something like an expanded treeview GUI widget rendered to an image. I haven't seen that done before myself using a plotting library.

CarForumPoster
Jun 26, 2013

⚡POWER⚡

Rocko Bonaparte posted:

The impression I got from Zero Gravitas' post is they wanted something like an expanded treeview GUI widget rendered to an image. I haven't seen that done before myself using a plotting library.

Sounds like plotting a decision tree except with >2 branches per root node. fastai uses grapviz for this, e.g.:

Hughmoris
Apr 21, 2007
Let's go to the abyss!
Regex wizards, I need your help.

I have a text document that contains answers to practice questions. I want to turn said questions/answers in to flashcards. I've already been able to regex and capture the question bank.

I'm having trouble creating a regex that will capture each answer. In the link below, you can see the format of the document. Basically, for every answer I want to capture all the characters up til the next answer.

The below regex101 hopefully illustrates the point. I'm missing the ability to deal with some sort of newline character (this was exported from a PDF to Word, then pasted to .txt).

https://regex101.com/r/1eDkVN/1

Any help you can provide is greatly appreciated!

Hughmoris fucked around with this message at 22:47 on Feb 21, 2020

KICK BAMA KICK
Mar 2, 2009

Hughmoris posted:

Regex wizards, I need your help.

I have a text document that contains answers to test questions. I want to turn said questions/answers in to flashcards. I've already been able to regex and capture the question bank.

I'm having trouble creating a regex that will capture each answer. In the link below, you can see the format of the document. Basically, for every answer I want to capture all the characters up til the next answer.

The below regex101 hopefully illustrates the point. I'm missing the ability to deal with some sort of newline character (this was exported from a PDF to Word, then pasted to .txt).

https://regex101.com/r/1eDkVN/1

Any help you can provide is greatly appreciated!
No wizard but I like figuring these out -- at a glance this looks like it works on the input provided? I think what I did was a) make your .* that grabs text indefinitely lazy, b) turn on the s flag for single-line mode, which causes the . to also match newlines and c) add a positive lookahead matching either the number-dot-tab pattern or the end of string as a place to stop.

e: forgot multiple digits on the lookahead, fixed: https://regex101.com/r/1BhLlg/2 ee: and removed an unnecessary pair of parentheses: https://regex101.com/r/1BhLlg/3

eee: Looks like you also forgot the possibility of multiple digits on the question numbers, and you'll probably want to capture those to match questions to answers, so: https://regex101.com/r/1BhLlg/4

OK I can't stop: with named groups to separately capture the question number, correct choice and full text of the answer: https://regex101.com/r/1BhLlg/5

KICK BAMA KICK fucked around with this message at 23:21 on Feb 21, 2020

Hughmoris
Apr 21, 2007
Let's go to the abyss!

KICK BAMA KICK posted:

No wizard but I like figuring these out -- at a glance this looks like it works on the input provided? I think what I did was a) make your .* that grabs text indefinitely lazy, b) turn on the s flag for single-line mode, which causes the . to also match newlines and c) add a positive lookahead matching either the number-dot-tab pattern or the end of string as a place to stop.

e: forgot multiple digits on the lookahead, fixed: https://regex101.com/r/1BhLlg/2 ee: and removed an unnecessary pair of parentheses: https://regex101.com/r/1BhLlg/3

eee: Looks like you also forgot the possibility of multiple digits on the question numbers, and you'll probably want to capture those to match questions to answers, so: https://regex101.com/r/1BhLlg/4

OK I can't stop: with named groups to separately capture the question number, correct choice and full text of the answer: https://regex101.com/r/1BhLlg/5

You are a scholar and a saint! Your magic worked like a charm. I had forgotten about the look-ahead feature.

Yesterday I was weeping at the thought of turning 450 practice questions in to Anki flashcards by copy/pasting from a PDF. I dusted off Python and hacked together a workable solution in about 30 minutes (a lot of it spent remembering how to use the regex module and CSV writer).

I love how easy Python can make things.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

CarForumPoster posted:

Sounds like plotting a decision tree except with >2 branches per root node. fastai uses grapviz for this, e.g.:

Apparently not, though:

Zero Gravitas posted:

Everything I google turns up decision trees which is not what im after; not least cos the flow is top down rather than bottom up.

My impression is some kind of tree renderer takes care of most of it but there's a peculiarity to the layout. I wonder if a similar view can be done if somehow one can enforce:

1. Parents are up and left of children
2. Lines connect parents to children by going down and right

CarForumPoster
Jun 26, 2013

⚡POWER⚡

Rocko Bonaparte posted:

Apparently not, though:


My impression is some kind of tree renderer takes care of most of it but there's a peculiarity to the layout. I wonder if a similar view can be done if somehow one can enforce:

1. Parents are up and left of children
2. Lines connect parents to children by going down and right

Comedy option, make it a DataFrame, plot it in matplotlib and save it as an image.

Seems like maybe all he needed is to add text to an image using PIL, nesting as needed.

Something like this example that is pulled straight from my rear end without testing
code:
from PIL import Image, ImageDraw, ImageFont

# get an image
base = Image.open('images/great_base_image.jpg')

# get a font
fnt = ImageFont.truetype('Pillow/Tests/fonts/FreeMono.ttf', 40)

# get a drawing context
d = ImageDraw.Draw(base)

# draw Parent
d.text((10,10), "Parent Assembly", font=fnt)
subassemblies = ['sa1','sa2']
spacing = 10
for sub in subassemblies:
	# draw subassemblies
	d.text((20,spacing), f"{sub}", font=fnt)
	# draw sub assembly lines, 1 horizontal and 1 vertical
	d.line((width, spacing), fill=128)
	d.line((spacing, width), fill=128)
	spacing +=10
d.show()
PIL Docs: https://pillow.readthedocs.io/en/3.1.x/reference/ImageDraw.html

CarForumPoster fucked around with this message at 02:29 on Feb 22, 2020

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
Yeah I guess there's always just drawing it. It looks like they went and hid though hahaha.

As for my own stuff:

I am trying to switch to a log configuration instead of a hard-coded one. There are a few things that are dynamically-calculated that I can't readily put in my configuration. The current tool allows for a different logging root directory and the log file is created using a certain signature. I saw something about using a filter to do this for the file handler, but it's also kind of clumsy. That stuff came from Stack Exchange back in 2012 or so; I hoped something newer came along that made this kind of thing easier.

What I'm thinking of doing is loading in the dictionary with some reserved words that I'll recursively replace with the dynamically-created settings if I find them. That's then fed into logging.config.dictConfig. So for a standard fileHander, the file path will be something like "%{logPath}%\stuff_%{timestamp}%\%{pidstamp}%.log".

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
Responding to myself since some time's elapsed:

Rocko Bonaparte posted:

I am trying to switch to a log configuration instead of a hard-coded one. There are a few things that are dynamically-calculated that I can't readily put in my configuration...

I've pretty much finished this all up and determined that there isn't any good moon magic for the dynamically-calculated part. I had to declare a standard in my strings to allow injection of the values coming from the outside, and I just replace them recursively in the dictionary before I feed them into logging.dictConfig. You might see me in the general thread asking for tools and standards for that kind of preprocessing.

KICK BAMA KICK
Mar 2, 2009

Does PyCharm (or a plugin) have any kind of shortcut where I can put the cursor on a function or class get the full dotted-path name to that from the project root? i.e., for some weird reason I want to run a specific test from an external command line and that would be more convenient than typing out the entire hierarchy of my test packages.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

KICK BAMA KICK posted:

Does PyCharm (or a plugin) have any kind of shortcut where I can put the cursor on a function or class get the full dotted-path name to that from the project root? i.e., for some weird reason I want to run a specific test from an external command line and that would be more convenient than typing out the entire hierarchy of my test packages.

I don't have PyCharm in front of me to look up what it's called, but I have Ctrl-Alt-Shift-C mapped to the action that does this.


edit: I think it's called "Copy Reference".

KICK BAMA KICK
Mar 2, 2009

Thermopyle posted:

I don't have PyCharm in front of me to look up what it's called, but I have Ctrl-Alt-Shift-C mapped to the action that does this.


edit: I think it's called "Copy Reference".
Amazing, thanks!

fuf
Sep 12, 2004

haha

fuf posted:

Thanks for the replies! Will keep working on it tomorrow. This is my first opportunity in this new job to do some actual coding so it's a nice change. :)

Here is my first pass at this little automation script. Posting just in case anyone can spot anything embarrassingly bad. Some actual developers are probably gonna look at it before they let us put it live so don't wanna look like too much of an idiot (no more than is strictly necessary I mean). Still not sure about the logging / exception stuff really.

code:
import pysftp
import os
import logging

# TODO: pass mode (push or pull) as parameter to script
mode = 'pull'

# LOGGING
# Log to file
logging.basicConfig(filename='log.log',
                    level=logging.INFO,  # Logging level: DEBUG, INFO, WARN
                    filemode='w',  # Overwrite log file each run
                    format='%(asctime)s %(message)s'  # Prepend timestamp
                    )

# VARIABLES
# Local paths
# TODO: Change to absolute paths when on server
script_path = os.path.dirname(os.path.realpath(__file__))
local_intray = os.path.join(script_path, 'intray\\')
local_outtray = os.path.join(script_path, 'outtray\\')
local_outtray_transferred = os.path.join(script_path, 'outtray_transferred')

# Remote paths
remote_intray = '/intray_test/'
remote_outtray = '/outtray_test/'
remote_outtray_transferred = '/outtray_transferred_test/'


# FUNCTIONS
def pull():
    """
    COPY all files from remote_outtray to local_intray
    """
    logging.info('Starting pull...')
    files = sftp.listdir(remote_outtray)
    logging.info("{} {}".format(len(files), 'files found in remote outtray to download'))
    for f in files:
        logging.info('Downloading ' + f)
        sftp.get(remote_outtray + f, local_intray + f)
    logging.info('Finished pull')


def push():
    """
    COPY all files from local_outtray to remote_intray
    """
    logging.info('Start push...')
    files = os.listdir(local_outtray)
    logging.info("{} {}".format(len(files), 'files found in local outtray for upload'))
    for f in files:
        logging.info('Uploading ' + f)
        sftp.put(local_outtray + f, remote_intray + f)
    logging.info('Finished push')


def tidy_local_files():
    """
    MOVE all files from local_outtray to local_outtray_transferred
    """
    logging.info('Start tidy local files...')
    files = os.listdir(local_outtray)
    logging.info("{} {}".format(len(files), 'files found in local outtray to move to local outtray_transferred'))
    for f in files:
        logging.info('Moving ' + f)
        os.rename(os.path.join(local_outtray, f), os.path.join(local_outtray_transferred, f))
    logging.info('Finished tidy local files')


def tidy_remote_files():
    """
    MOVE all files from remote_outtray to remote_outtray_transferred
    TODO: This breaks if file already exists in outtray_transferred...
    """
    logging.info('Start tidy remote files...')
    files = sftp.listdir(remote_outtray)
    logging.info("{} {}".format(len(files), 'files found in remote outtray to move to remote outtray_transferred'))
    for f in files:
        sftp.rename(remote_outtray + f, remote_outtray_transferred + f)
    logging.info('Finished tidy remote files')

# SCRIPT

try:
    logging.info('Starting script...')
    with pysftp.Connection([blah blah blah]) as sftp:
        if mode == 'push':
            push()
            tidy_local_files()
        elif mode == 'pull':
            pull()
            tidy_remote_files()
        else:
            raise Exception('Invalid mode specified. Exiting...')
    logging.info('Script finished without errors')

except Exception as e:
    logging.exception('Failed with Exception:')
    raise Exception('Script exited with error, check log for details')

Nippashish
Nov 2, 2005

Let me see you dance!

fuf posted:

Here is my first pass at this little automation script. Posting just in case anyone can spot anything embarrassingly bad. Some actual developers are probably gonna look at it before they let us put it live so don't wanna look like too much of an idiot (no more than is strictly necessary I mean). Still not sure about the logging / exception stuff really.

The only non-nitpicky thing I see here is that sftp should really be a parameter to each of the functions that use it. Right now they all reference a global "sftp" variable, which is generally not good practice (the exceptions to this are module imports, and constants). I usually like to write the main part of my scripts inside a function and then call that function to run the script, in part because it makes it hard to use globals like this by accident. For example, like this:
code:
... # all the stuff before SCRIPT

def main():
    ... # code from the SCRIPT part here

# These two lines call 'main()' to run the script
if __name__ == '__main__':
    main()
You'll notice if you try this that your functions can't see sftp anymore, but you can pass it to them as an arguments.

fuf
Sep 12, 2004

haha

Nippashish posted:

The only non-nitpicky thing I see here is that sftp should really be a parameter to each of the functions that use it. Right now they all reference a global "sftp" variable, which is generally not good practice (the exceptions to this are module imports, and constants). I usually like to write the main part of my scripts inside a function and then call that function to run the script, in part because it makes it hard to use globals like this by accident.

ahhhh, clever, thanks. I've rewritten it following your structure.

Hollow Talk
Feb 2, 2014
Also, depending on your python version (anything >=3.6 I think?), I would replace the string format stuff for logging with f-strings, which are both faster and more readable.

https://www.python.org/dev/peps/pep-0498/

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

There's nothing wrong with using the os.path stuff, but I'd be using pathlib on 3.4 and up just because I like it's interface better.

DoctorTristan
Mar 11, 2006

I would look up into your lifeless eyes and wave, like this. Can you and your associates arrange that for me, Mr. Morden?

Hollow Talk posted:

Also, depending on your python version (anything >=3.6 I think?), I would replace the string format stuff for logging with f-strings, which are both faster and more readable.

https://www.python.org/dev/peps/pep-0498/

The logging module’s printf-style formatting can be even faster, since it won’t evaluate the message if the logging level means it’s not going to be logged. Of course this makes your logging calls a lot uglier.

fuf
Sep 12, 2004

haha

Hollow Talk posted:

Also, depending on your python version (anything >=3.6 I think?), I would replace the string format stuff for logging with f-strings, which are both faster and more readable.

https://www.python.org/dev/peps/pep-0498/

Ah that's cool. Speed isn't really an issue but more readable is definitely good.

Annoyingly the server has python 2.6.6 currently, and it might be hard to request an upgrade unless there's a good reason.

The python version might be an issue because I've been using argparse to pass command line arguments (to specify "push" or "pull" mode) and I don't think that's included in 2.6. I'll have to come up with another way or request an upgrade.

Thermopyle posted:

There's nothing wrong with using the os.path stuff, but I'd be using pathlib on 3.4 and up just because I like it's interface better.

This looks good but same problem with the python version here unfortunately.

Antigravitas
Dec 8, 2019

Die Rettung fuer die Landwirte:
Python 2.6 is even more EOL than what's EOL but still supported by distros (2.7).

Even Debian oldstable has Python 3.5 and 2.7 in its repos. And Debian old-oldstable has 2.7.9. Even CentOS 7 has 2.7!!

QuarkJets
Sep 8, 2008

Yeah I think 2.6 is CentOS 6 era. Yikes, but I can't honestly say that my orgs don't have any older servers kicking around for stupid/bad reasons

If you're allowed to install software, then you could at least set up a virtual environment with a newer version of python. I'd use Anaconda for this but everyone has their own preferences

Proteus Jones
Feb 28, 2013



QuarkJets posted:

Yeah I think 2.6 is CentOS 6 era. Yikes, but I can't honestly say that my orgs don't have any older servers kicking around for stupid/bad reasons

If you're allowed to install software, then you could at least set up a virtual environment with a newer version of python. I'd use Anaconda for this but everyone has their own preferences

One note re: Anaconda. If it’s in a corporate environment I’m pretty sure you need to pay for a license, so if budget is an issue it may not be an option.

NinpoEspiritoSanto
Oct 22, 2013




Pyenv if the tool chain can still build it as another option.

pmchem
Jan 22, 2010


Proteus Jones posted:

One note re: Anaconda. If it’s in a corporate environment I’m pretty sure you need to pay for a license, so if budget is an issue it may not be an option.

I don't think that's the case? They sell Anaconda Enterprise but it's for the plus-up in features related to deployment/management of installations.

Nippashish
Nov 2, 2005

Let me see you dance!

fuf posted:

The python version might be an issue because I've been using argparse to pass command line arguments (to specify "push" or "pull" mode) and I don't think that's included in 2.6. I'll have to come up with another way or request an upgrade.

Python 2.6 is very old, but sometimes its not worth it to fight the status quo. Either way it is worth learning how to use virtual environments so that you can develop locally using whatever version of python is on the server you need to deploy to (even if you can swing an upgrade, who knows if they'll upgrade to the same version of python you happen to have locally). If you make a virtual environment with python 2.6 and develop using that it will prevent you from using features that don't exist where the code needs to run.

Proteus Jones
Feb 28, 2013



pmchem posted:

I don't think that's the case? They sell Anaconda Enterprise but it's for the plus-up in features related to deployment/management of installations.

You’re right, I was mistaking it with a different free-for-individual-paid-for-commercial product. Sorry for the confusion.

fuf
Sep 12, 2004

haha
Thanks for the replies.

The servers are definitely CentOS, not sure what version, but it doesn't surprise me at all if they are on a really old version and an old version of python. There's a lot of institutional sluggishness here.

It's not really something I want to stick my neck out about any time soon so I'll probably try and limit myself to stuff that works on 2.6.

Setting up a new virtual environment with 2.6 is a very good idea.

Adbot
ADBOT LOVES YOU

QuarkJets
Sep 8, 2008

iirc, CentOS5 has Python 2.4, CentOS6 had Python 2.6, and CentOS7 had Python 2.7 as the default versions for system python.

But there are python3 RPMs available in the EPEL, plus a whole bunch of other python packages that you may want. You should ask your IT people about access to the EPEL, or even just try searching for "python3" with yum and see if the EPEL (or some other repository with python3 in it) is enabled. You'd probably be on an older version of python3 but that's still better than being on 2.6 (imo).

I guess this would be more than doing nothing, but since the RPMs are coming from official repositories IT shouldn't take any issue with it.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply