Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
62b10d7
PY3: Replace "import thread" with "from six.moves import _thread as t…
chrisburr Aug 15, 2020
b9b6299
PY3: Replace "import urlparse" with "import six.moves.urllib.parse"
chrisburr Aug 15, 2020
4f3f839
PY3: Remove Python version check on import
chrisburr Aug 15, 2020
d285b56
PY3: Encode strings as UTF-8 before using hashlib.md5
chrisburr Aug 15, 2020
604de9c
PY3: Allow importing DEncode in Python 3 without actually porting it
chrisburr Aug 15, 2020
4bdc9b0
PY3: Replace "import Queue" with "from six.moves import queue as Queue"
chrisburr Aug 15, 2020
331c7ed
PY3: Replace "itertools.izip_longest" with "six.moves.zip_longest"
chrisburr Aug 15, 2020
58d240d
PY3: Get urllib2.URLError from six.moves.urllib_error
chrisburr Aug 15, 2020
846d8a6
PY3: Escape backslash in Core/Utilities/Grid.py
chrisburr Aug 15, 2020
0716316
PY3: Minimal types fixes to make pytest discovery functional
chrisburr Aug 15, 2020
5a66509
PY3: Remove MySQLdb.server_init if using mysqlclient
chrisburr Aug 15, 2020
7ece6c3
PY3: Replace StringIO with six.StringIO and six.BytesIO
chrisburr Aug 16, 2020
69f058b
PY3: Fix string type checking in Core/Utilities/Time.py
chrisburr Aug 16, 2020
8a4eaf1
PY3: Fallback to subprocess.getstatusoutput for commands.getstatusoutput
chrisburr Aug 16, 2020
c8c1f9d
Run pytest discovery with Python 3
chrisburr Aug 15, 2020
80e5466
Fix pycodestyle indentation errors
chrisburr Aug 17, 2020
bfa7ae9
Spelling corrections from code review
chrisburr Aug 17, 2020
fd23b16
Fix typo for test_types in Test_Encode.py
chrisburr Aug 21, 2020
5884f20
Fix typo in .github/workflows/basic-python3.yml
chrisburr Aug 25, 2020
305202c
Add pycurl and subprocess32 to environment-py3.yml
chrisburr Aug 25, 2020
5166756
PY3: Execute pytest skipping all directories
chrisburr Aug 17, 2020
54d6598
PY3: Run basic tests for ConfigurationSystem
chrisburr Aug 17, 2020
1d2af4b
PY3: Run most tests for Core
chrisburr Aug 21, 2020
6d1a7b3
PY3: Replace use of itervalues, iterkeys and iteritems
chrisburr Aug 21, 2020
ef16451
PY3: Make JDL and Workflow XML deterministic
chrisburr Aug 21, 2020
dc35239
PY3: Run tests for Interfaces
chrisburr Aug 21, 2020
ff82062
PY3: Fix use of dict.keys()
chrisburr Aug 24, 2020
7657856
PY3: Remove use of xrange
chrisburr Aug 24, 2020
1e6ae9d
PY3: Enable Resources unit tests
chrisburr Aug 25, 2020
343b8a3
PY3: Enable DataManagementSystem unit tests
chrisburr Aug 25, 2020
31ab404
PY3: Enable AccountingSystem and MonitoringSystem unit tests
chrisburr Aug 25, 2020
2eb6aef
PY3: Enable FrameworkSystem
chrisburr Aug 25, 2020
714a78d
PY3: Enable RequestManagementSystem tests
chrisburr Aug 25, 2020
5f8df52
PY3: Enable ResourceStatusSystem tests
chrisburr Aug 25, 2020
3d97a01
PY3: Enable WorkloadManagementSystem tests
chrisburr Aug 25, 2020
79564d4
PY3: Enable ProductionSystem, StorageManagementSystem and Workflow tests
chrisburr Aug 25, 2020
03d06f5
PY3: Enable TransformationSystem tests
chrisburr Aug 25, 2020
f5de43d
PY3: Enable unit tests except Core/DISET
chrisburr Aug 25, 2020
315a500
Core: use M2Crypto API for allowing proxy certificates
chaen Dec 20, 2019
21bcb92
PY3: Enable Core/DISET tests
chrisburr Aug 25, 2020
e1edc3b
Fix pycodestyle errors
chrisburr Aug 25, 2020
480561f
Support flakey unit tests and avoid https://github.com/pytest-dev/pyt…
chrisburr Aug 26, 2020
8612127
Review comments
chrisburr Aug 28, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
42 changes: 42 additions & 0 deletions .github/workflows/basic-python3.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Python 3 tests

on: [push, pull_request]

jobs:
check:
runs-on: ubuntu-latest
if: github.event_name != 'push' || github.repository == 'DIRACGrid/DIRAC'
timeout-minutes: 30

strategy:
fail-fast: False
matrix:
command:
# TODO These three tests fail on Python 3:
# * `test_BaseType_Unicode` and `test_nestedStructure` fail due to
# DISET's string and unicode types being poorly defined
# * `testLockedClass` deadlocks frequently due to the use of
# self.__processThread._Thread__stop(). Officially "threads
# cannot be destroyed, stopped, suspended, resumed, or
# interrupted" so the code should be rewritten to follow the
# supported alternative: "If you want your threads to stop
# gracefully, make them non-daemonic and use a suitable
# signalling mechanism such as an Event."
- pytest --no-cov -k 'not test_BaseType_Unicode and not test_nestedStructure and not testLockedClass'

steps:
- uses: actions/checkout@v2
- name: Fail-fast for outdated pipelines
run: .github/workflows/fail-fast.sh
- name: Prepare environment
run: |
conda env create --name dirac-testing --file environment-py3.yml
- name: Run tests
run: |
source "${CONDA}/bin/activate"
conda activate dirac-testing
set -euxo pipefail
export PYTHONPATH=${PWD%/*}
${{ matrix.command }}
env:
REFERENCE_BRANCH: ${{ github['base_ref'] || github['head_ref'] }}
4 changes: 2 additions & 2 deletions AccountingSystem/Agent/NetworkAgent.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def updateNameDictionary(self):
return S_ERROR('Unable to fetch perfSONAR endpoints from CS.')

tmpDict = {}
for path, value in result['Value'].iteritems():
for path, value in result['Value'].items():
if value == 'True':
elements = path.split('/')
diracName = elements[4]
Expand Down Expand Up @@ -211,7 +211,7 @@ def processMessage(self, headers, body):
OWDMax = 0
total = 0
count = 0
for value, items in metricData.iteritems():
for value, items in metricData.items():
floatValue = float(value)
total += floatValue * items
count += items
Expand Down
2 changes: 1 addition & 1 deletion AccountingSystem/Service/DataStoreHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def export_removeRegisters(self, entriesList):
for entry in entriesList:
if len(entry) != 4:
return S_ERROR("Invalid records")
for i in xrange(len(entry)):
for i in range(len(entry)):
if not isinstance(entry[i], expectedTypes[i]):
return S_ERROR("%s field in the records should be %s" % (i, expectedTypes[i]))
ok = 0
Expand Down
4 changes: 2 additions & 2 deletions AccountingSystem/private/MainReporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def __calculateReportHash(self, reportRequest):
epoch = requestToHash[key]
requestToHash[key] = epoch - epoch % granularity
md5Hash = hashlib.md5()
md5Hash.update(repr(requestToHash))
md5Hash.update(self.setup)
md5Hash.update(repr(requestToHash).encode())
md5Hash.update(self.setup.encode())
return md5Hash.hexdigest()

def generate(self, reportRequest, credDict):
Expand Down
2 changes: 1 addition & 1 deletion AccountingSystem/private/Plotters/PilotPlotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def _plotJobsPerPilot(self, reportRequest, plotInfo, filename):
'endtime': reportRequest['endTime'],
'span': plotInfo['granularity'],
'ylabel': "jobs/pilot",
'normalization': max(x for y in plotInfo['data'].itervalues() for x in y.itervalues())}
'normalization': max(x for y in plotInfo['data'].values() for x in y.values())}
return self._generateQualityPlot(filename, plotInfo['data'], metadata)

def _reportTotalNumberOfPilots(self, reportRequest):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import pprint
import sys
import urlparse
from six.moves.urllib import parse as urlparse
import cgi
from DIRAC import gLogger
from DIRAC.Core.Base import Script
Expand Down
8 changes: 4 additions & 4 deletions ConfigurationSystem/Agent/GOCDB2CSAgent.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def execute(self):
"""

# __functionMap is at the end of the class definition
for option, functionCall in GOCDB2CSAgent.__functionMap.iteritems():
for option, functionCall in GOCDB2CSAgent.__functionMap.items():
optionValue = self.am_getOption(option, True)
if optionValue:
result = functionCall(self)
Expand Down Expand Up @@ -157,12 +157,12 @@ def __preparePerfSONARConfiguration(self, endpointList):

split = endpoint['DIRACSITENAME'].split('.')
path = cfgPath(rootPath, split[0], endpoint['DIRACSITENAME'], extPath, endpoint['HOSTNAME'])
for name, defaultValue in options.iteritems():
for name, defaultValue in options.items():
newConfiguration[cfgPath(path, name)] = defaultValue

# get current configuration
currentConfiguration = {}
for option in options.iterkeys():
for option in options.keys():
result = gConfig.getConfigurationTree(rootPath, extPath + '/', '/' + option)
if not result['OK']:
log.error("getConfigurationTree() failed with message: %s" % result['Message'])
Expand Down Expand Up @@ -242,7 +242,7 @@ def __updateConfiguration(self, setElements=None, delElements=None):
log.debug('Begin function ...')

# assure existence and proper value of a section or an option
for path, value in setElements.iteritems():
for path, value in setElements.items():

if value is None:
section = path
Expand Down
4 changes: 2 additions & 2 deletions ConfigurationSystem/Client/Helpers/CSGlobals.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
__RCSID__ = "$Id$"

import imp
import six
from DIRAC.Core.Utilities.DIRACSingleton import DIRACSingleton


@six.add_metaclass(DIRACSingleton)
class Extensions(object):
__metaclass__ = DIRACSingleton

def __init__(self):
self.__modules = {}
self.__orderedExtNames = []
Expand Down
2 changes: 1 addition & 1 deletion ConfigurationSystem/Client/Helpers/Operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
from __future__ import print_function

import six
import thread
from six.moves import _thread as thread
import os
from diraccfg import CFG
from DIRAC import S_OK, S_ERROR, gConfig
Expand Down
2 changes: 1 addition & 1 deletion ConfigurationSystem/Client/Helpers/Resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

__RCSID__ = "$Id$"

import urlparse
from six.moves.urllib import parse as urlparse
from distutils.version import LooseVersion # pylint: disable=no-name-in-module,import-error

import six
Expand Down
2 changes: 1 addition & 1 deletion ConfigurationSystem/Client/PathFinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

__RCSID__ = "$Id$"

import urlparse
from six.moves.urllib import parse as urlparse

from DIRAC.Core.Utilities import List
from DIRAC.ConfigurationSystem.Client.ConfigurationData import gConfigurationData
Expand Down
9 changes: 3 additions & 6 deletions ConfigurationSystem/Client/Utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import re
import socket
from urlparse import urlparse
from six.moves.urllib.parse import urlparse

import six

Expand Down Expand Up @@ -274,9 +274,7 @@ def addToChangeSet(entry, changeSet):
if submissionMode == "Unknown" and newSubmissionMode:
addToChangeSet((ceSection, 'SubmissionMode', submissionMode, newSubmissionMode), changeSet)

queues = ceInfo['Queues'].keys()
for queue in queues:
queueInfo = ceInfo['Queues'][queue]
for queue, queueInfo in ceInfo['Queues'].items():
queueStatus = queueInfo['GlueCEStateStatus']
queueSection = cfgPath(ceSection, 'Queues', queue)
queueDict = {}
Expand Down Expand Up @@ -455,8 +453,7 @@ def getGridSRMs(vo, bdiiInfo=None, srmBlackList=None, unUsed=False):

srmSeDict = {}
for site in siteSRMDict:
srms = siteSRMDict[site].keys()
for srm in srms:
for srm in siteSRMDict[site]:
if seBdiiDict.get(site, {}).get('SEs', {}).get(srm, {}):
srmSeDict.setdefault(site, {})
srmSeDict[site].setdefault(srm, {})
Expand Down
2 changes: 1 addition & 1 deletion ConfigurationSystem/private/ConfigurationClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ def getConfigurationTree(self, root='', *filters):
if not options['OK']:
return S_ERROR("getOptionsDict() failed with message: %s" % options['Message'])

for key, value in options['Value'].iteritems():
for key, value in options['Value'].items():
path = cfgPath(root, key)
addOption = True
for substr in filters:
Expand Down
2 changes: 1 addition & 1 deletion ConfigurationSystem/private/ConfigurationData.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import os.path
import zlib
import zipfile
import thread
from six.moves import _thread as thread
import time
import DIRAC

Expand Down
2 changes: 1 addition & 1 deletion ConfigurationSystem/private/Refresher.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
__RCSID__ = "$Id$"

import threading
import thread
from six.moves import _thread as thread
import time
import random
from DIRAC.ConfigurationSystem.Client.ConfigurationData import gConfigurationData
Expand Down
7 changes: 3 additions & 4 deletions ConfigurationSystem/scripts/dirac-admin-add-resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import re
import os
import shlex
from urlparse import urlparse
from six.moves.urllib.parse import urlparse

from DIRAC.Core.Base import Script
from DIRAC import gLogger, exit as DIRACExit, S_OK
Expand Down Expand Up @@ -97,7 +97,7 @@ def checkUnusedCEs():
result = getDIRACSiteName(site)
if result['OK']:
diracSite = ','.join(result['Value'])
ces = siteDict[site].keys() # pylint: disable=no-member
ces = list(siteDict[site])
if ces:
gLogger.notice(" %s, DIRAC site %s" % (site, diracSite))
for ce in ces:
Expand All @@ -120,8 +120,7 @@ def checkUnusedCEs():
for site in siteDict:
# Get the country code:
country = ''
ces = siteDict[site].keys() # pylint: disable=no-member
for ce in ces:
for ce in siteDict[site]:
country = ce.strip().split('.')[-1].lower()
if len(country) == 2:
break
Expand Down
2 changes: 1 addition & 1 deletion ConfigurationSystem/scripts/dirac-admin-bdii-info.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def showInfo(result, info):
if info == 'site-se' or info == 'all':
print("SE: %s \n{" % element.get('GlueSEUniqueID', 'Unknown'))

for item in element.iteritems():
for item in element.items():
print(" %s: %s" % item)
print("}")

Expand Down
3 changes: 3 additions & 0 deletions Core/Base/API.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ def __getstate__(self):
# because of the thread locks
if isinstance(state['log'], Logging):
state['log'] = state['log'].getSubName()
# In Python 3 PrettyPrinter can't be pickled
del state['pPrint']
return state

def __setstate__(self, state):
Expand All @@ -101,6 +103,7 @@ def __setstate__(self, state):
# due to the thread locks
if isinstance(state['log'], six.string_types):
self.log = gLogger.getSubLogger(state['log'])
self.pPrint = pprint.PrettyPrinter()

#############################################################################

Expand Down
32 changes: 16 additions & 16 deletions Core/Base/ExecutorMindHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
from __future__ import division
from __future__ import print_function

import types
import pprint

import six
from DIRAC import gLogger
from DIRAC.Core.Utilities.ReturnValues import S_OK, S_ERROR, isReturnStructure
from DIRAC.Core.Utilities.ThreadScheduler import gThreadScheduler
Expand All @@ -16,21 +16,21 @@

class ExecutorMindHandler(RequestHandler):

MSG_DEFINITIONS = {'ProcessTask': {'taskId': (types.IntType, types.LongType),
'taskStub': types.StringTypes,
'eType': types.StringTypes},
'TaskDone': {'taskId': (types.IntType, types.LongType),
'taskStub': types.StringTypes},
'TaskFreeze': {'taskId': (types.IntType, types.LongType),
'taskStub': types.StringTypes,
'freezeTime': (types.IntType, types.LongType)},
'TaskError': {'taskId': (types.IntType, types.LongType),
'errorMsg': types.StringTypes,
'taskStub': types.StringTypes,
'eType': types.StringTypes},
'ExecutorError': {'taskId': (types.IntType, types.LongType),
'errorMsg': types.StringTypes,
'eType': types.StringTypes}}
MSG_DEFINITIONS = {'ProcessTask': {'taskId': six.integer_types,
'taskStub': six.string_types,
'eType': six.string_types},
'TaskDone': {'taskId': six.integer_types,
'taskStub': six.string_types},
'TaskFreeze': {'taskId': six.integer_types,
'taskStub': six.string_types,
'freezeTime': six.integer_types},
'TaskError': {'taskId': six.integer_types,
'errorMsg': six.string_types,
'taskStub': six.string_types,
'eType': six.string_types},
'ExecutorError': {'taskId': six.integer_types,
'errorMsg': six.string_types,
'eType': six.string_types}}

class MindCallbacks(ExecutorDispatcherCallbacks):

Expand Down
13 changes: 7 additions & 6 deletions Core/Base/SQLAlchemyDB.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

__RCSID__ = "$Id$"

import six
import datetime
from sqlalchemy import create_engine, desc, exc
from sqlalchemy.engine.reflection import Inspector
Expand Down Expand Up @@ -189,13 +190,13 @@ def select(self, table, params):
select = Query(columns, session=session)

# query conditions
for columnName, columnValue in params.iteritems():
for columnName, columnValue in params.items():
if not columnValue:
continue
column_a = getattr(table_c, columnName.lower())
if isinstance(columnValue, (list, tuple)):
select = select.filter(column_a.in_(list(columnValue)))
elif isinstance(columnValue, (basestring, datetime.datetime, bool)):
elif isinstance(columnValue, six.string_types + (datetime.datetime, bool)):
select = select.filter(column_a == columnValue)
else:
self.log.error("type(columnValue) == %s" % type(columnValue))
Expand All @@ -206,7 +207,7 @@ def select(self, table, params):
column_a = getattr(table_c, newer[0].lower())
select = select.filter(column_a > newer[1])
if order:
order = [order] if isinstance(order, basestring) else list(order)
order = [order] if isinstance(order, six.string_types) else list(order)
column_a = getattr(table_c, order[0].lower())
if len(order) == 2 and order[1].lower() == 'desc':
select = select.order_by(desc(column_a))
Expand Down Expand Up @@ -268,13 +269,13 @@ def delete(self, table, params):

try:
deleteQuery = Query(table_c, session=session)
for columnName, columnValue in params.iteritems():
for columnName, columnValue in params.items():
if not columnValue:
continue
column_a = getattr(table_c, columnName.lower())
if isinstance(columnValue, (list, tuple)):
deleteQuery = deleteQuery.filter(column_a.in_(list(columnValue)))
elif isinstance(columnValue, (basestring, datetime.datetime, bool)):
elif isinstance(columnValue, six.string_types + (datetime.datetime, bool)):
deleteQuery = deleteQuery.filter(column_a == columnValue)
else:
self.log.error("type(columnValue) == %s" % type(columnValue))
Expand All @@ -285,7 +286,7 @@ def delete(self, table, params):
column_a = getattr(table_c, newer[0].lower())
deleteQuery = deleteQuery.filter(column_a > newer[1])
if order:
order = [order] if isinstance(order, basestring) else list(order)
order = [order] if isinstance(order, six.string_types) else list(order)
column_a = getattr(table_c, order[0].lower())
if len(order) == 2 and order[1].lower() == 'desc':
deleteQuery = deleteQuery.order_by(desc(column_a))
Expand Down
2 changes: 1 addition & 1 deletion Core/DISET/MessageClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def _initialize(self):

def __generateUniqueClientName(self):
hashStr = ":".join((Time.toString(), str(random.random()), Network.getFQDN(), gLogger.getName()))
hexHash = md5(hashStr).hexdigest()
hexHash = md5(hashStr.encode()).hexdigest()
return hexHash

def setUniqueName(self, uniqueName):
Expand Down
Loading