'Azure pipeline can't find the user created python module
I am attempting to run tests from a python module using Azure DevOps. I've got a pipeline build set up to build of a yml file and also using classic editor. I'm getting an error that my module name on my imports is not right. When I run this locally, it works just fine.
My Repo structure:
I'm running my test using this command as a batch file:
cd testcases
pytest -v test_msoffice.py
and gives me error:
______________________ ERROR collecting test_msoffice.py ______________________
ImportError while importing test module 'D:\a\1\s\testcases\test_msoffice.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
test_msoffice.py:7: in <module>
from util import utility_method_class
E ModuleNotFoundError: No module named util
Someone please help me.
Solution 1:[1]
Pretty sure this is related to Azure DevOps Pipelines - Python - ModuleNotFoundError despite sys.path.append() or setting PYTHONPATH, where it says:
After talking to the Azure DevOps Support, I now know that my issue is a bug within DevOps-Pipelines at the moment.
Solution 2:[2]
I ran into the same symptoms over the last two days.
I assume locally your package is in a directory called "util", with (or as per your comment without) an __init__.py
file. This leads python to recognise all modules under that directory as belonging to the utils package. (From Python 3.something python will manage "namespace references" to the local directory structure without __init__.py
)
On the Pipeline agent the code is directly copied into D:\a\1\s\ - therefore python will consider the package to be called "s"
I found the following workaround: include a script in the pipeline to move the source code into a new suitably named directory and then test it there.
My Pipeline YAML looks like this. It is based on the assumption that your ADO project is named the same as your package - so in your case "util" and is set up for ubuntu / bash. If you must test on windows agents then the scripting will need porting, or you can switch to ubuntu agents and copy the whole thing.
# Python package
# Create and test a Python package on multiple Python versions.
# Add steps that analyze code, save the dist with the build record, publish to a PyPI-compatible index, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/python
trigger:
- azure-pipelines
- master
- pipeline/*
variables:
PythonPackagePath: ORIGINALVALUE
pool:
vmImage: ubuntu-latest
strategy:
matrix:
# Python27:
# python.version: '2.7'
# Python35:
# python.version: '3.5'
# Python36:
# python.version: '3.6'
# Python37:
# python.version: '3.7'
Python310:
python.version: '3.10'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(python.version)'
displayName: 'Use Python $(python.version)'
- script: |
cd $(System.DefaultWorkingDirectory)
export ParentDir=${PWD%/*}
echo Setting PythonPackagePath to $ParentDir/$(System.TeamProject)
echo "##vso[task.setvariable variable=PythonPackagePath;]$ParentDir/$(System.TeamProject)"
displayName: 'Set Package Path'
- script: |
echo PythonPackagePath is $(PythonPackagePath)
echo Moving files from $(System.DefaultWorkingDirectory) to $(PythonPackagePath)
mv $(System.DefaultWorkingDirectory) $(PythonPackagePath)
echo SymLinking old Working Directory back in case needed
ln -s $(PythonPackagePath) $(System.DefaultWorkingDirectory)
ls -l $(System.DefaultWorkingDirectory)/..
displayName: 'Move Working Directory'
- script: |
python -m pip install --upgrade pip
pip install -r requirements.txt
displayName: 'Install dependencies'
# continueOnError: true
- script: |
export PYTHONPATH=$(PythonPackagePath)
echo PYTHONPATH is set to $PYTHONPATH
cd $(PythonPackagePath)
echo Working in:
pwd
pip install pytest pytest-azurepipelines
pip install pytest-cov
pytest --cov=. --cov-report=xml
displayName: 'pytest'
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: '$(PythonPackagePath)/**/coverage.xml'
A few traps I fell into along the way:
- ADO pipeline variables of the form
$(VariableName)
are resolved when the step starts, not when the line is reached - so you need to set the variable in a previous step before using it. - bash will keep a relative directory reference in place in a variable. So you cannot
export ParentDir=..
norexport ParentDir=$(System.DefaultWorkingDirectory)/..
in the first case ParentDir is always the parent of the current working directory, in the second the symlinking will fail due to circular references. The RegEx${PWD%/*}
gets the value of the current directory and returns the value up to the last slash. - pytest does not like following symlinks - so you cannot simply
ln -s path/to/code/s path/to/code/PackageName
pytest will still consider the package to be called s - Setting
PYTHONPATH
is not strictly necessary, running pytest from the right directory seems to be the most stable option in thie configuration - I had a few issues with getting code coverage to publish properly. I think it also doesn't like symlinks - so don't forget to update the path in the relevant step as well.
This works regardless of whether tests are in a subfolder. My overall structure is:
FooBar
__init__.py
¦
-- Doomsday
__init__.py
Fuel.py
test_Fuel.py
...
¦
-- Utils
__init__.py
Maths.py
...
¦
--test
test_Maths1.py
test_Maths2.py
...
where:
- FooBar is also the name of my project in ADO
- pytest tests for Doomsday are in the Doomsday directory
- pytest tests for Utils are in a subfolder
- references are in the form
from FooBar.Utils.Maths import prod
and these work correctly
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | laike9m |
Solution 2 | MusicalNinja |