Search code examples
azure-functionspython-3.8joblibazure-auto-ml

AttributeError: module 'typing' has no attribute '_ClassVar' - Azure Function


I am having a problem deploying Azure Function with a trained .pkl model on Azure ML when loading it using joblib.load('model.pkl'). Locally on Windows in Visual Studio Code works, doesn't work after deployment to Azure Fuction. I am using python 3.8.6 My requirements.txt:

azure-functions
joblib==0.14.1
numpyencoder==0.3.0
numpy==1.19.0
azureml-automl-runtime==1.49.0

My code:

import logging
import azure.functions as func
import os
import json
import pandas as pd
from numpyencoder import NumpyEncoder

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Predict business classification')

    max_prediction_count = 3
    logging.info('Predict business classification - before')

    model = joblib.load('model.pkl')

    logging.info('Predict business classification - after')

    company_name = req.params.get('name')
    limit =  req.params.get('limit')
    max_predictions = max_prediction_count
    if limit:
        try:
            max_predictions = int(limit)
        except ValueError:
            max_predictions = max_prediction_count
    
    predictions = get_predictions(model, company_name)
    
    
    
    labels = model.classes_
    
    res = predictions[0].tolist()
    res = [{'id': labels[i], 'confidence': x * 100} for i, x in enumerate(res)]
    res.sort(key=lambda d: d['confidence'], reverse=True)
    result = res[:max_predictions]
    return  func.HttpResponse(body=json.dumps(result, cls=NumpyEncoder) , mimetype="application/json",  status_code=200)

def get_predictions(model, company_name):
    input_sample = pd.DataFrame(data=[{
        "IN_CompanyNameClean": company_name,
    }])

    predictions = model.predict_proba(input_sample)
    return predictions

Result: Failure Exception: AttributeError: module 'typing' has no attribute '_ClassVar' Stack: File "/azure-functions-host/workers/python/3.8/LINUX/X64/azure_functions_worker/dispatcher.py", line 452, in _handle__invocation_request call_result = await self._loop.run_in_executor( File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run result = self.fn(*self.args, **self.kwargs) File "/azure-functions-host/workers/python/3.8/LINUX/X64/azure_functions_worker/dispatcher.py", line 718, in _run_sync_func return ExtensionManager.get_sync_invocation_wrapper(context, File "/azure-functions-host/workers/python/3.8/LINUX/X64/azure_functions_worker/extension.py", line 215, in _raw_invocation_wrapper result = function(**args) File "/home/site/wwwroot/predictBusinessClassification/__init__.py", line 34, in main model = joblib.load('model.pkl') File "/home/site/wwwroot/.python_packages/lib/site-packages/joblib/numpy_pickle.py", line 605, in load obj = _unpickle(fobj, filename, mmap_mode) File "/home/site/wwwroot/.python_packages/lib/site-packages/joblib/numpy_pickle.py", line 529, in _unpickle obj = unpickler.load() File "/usr/local/lib/python3.8/pickle.py", line 1212, in load dispatch[key[0]](self) File "/home/site/wwwroot/.python_packages/lib/site-packages/joblib/numpy_pickle.py", line 342, in load_build Unpickler.load_build(self) File "/usr/local/lib/python3.8/pickle.py", line 1705, in load_build setstate(state) File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/featurization/data_transformer.py", line 998, in __setstate__ new_data_transformer = DataTransformer() File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/featurization/data_transformer.py", line 198, in __init__ from azureml.automl.runtime.sweeping.meta_sweeper import MetaSweeper File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/sweeping/meta_sweeper.py", line 36, in <module> from ..scoring import Scorers, AbstractScorer File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/scoring/__init__.py", line 5, in <module> from .abstract_scorer import AbstractScorer File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/scoring/abstract_scorer.py", line 12, in <module> from azureml.automl.runtime.shared.metrics import is_better File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/shared/metrics.py", line 18, in <module> from azureml.automl.runtime import _ml_engine File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/_ml_engine/__init__.py", line 6, in <module> from .ml_engine import convert_to_onnx, featurize, validate, run_ensemble_selection File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/_ml_engine/ml_engine.py", line 52, in <module> from azureml.automl.runtime._ml_engine.validation import AbstractRawExperimentDataValidator, \ File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/_ml_engine/validation/__init__.py", line 7, in <module> from .featurization_config_data_validator import FeaturizationConfigDataValidator File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/_ml_engine/validation/featurization_config_data_validator.py", line 19, in <module> from azureml.automl.runtime import _data_transformation_utilities File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/automl/runtime/_data_transformation_utilities.py", line 41, in <module> from azureml.core import Run File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/core/__init__.py", line 16, in <module> from .workspace import Workspace File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/core/workspace.py", line 22, in <module> from azureml._project import _commands File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/_project/_commands.py", line 23, in <module> from azureml._project.project_engine import ProjectEngineClient File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/_project/project_engine.py", line 12, in <module> import azureml._project.project_manager as project_manager File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/_project/project_manager.py", line 9, in <module> from azureml._project.ignore_file import AmlIgnoreFile File "/home/site/wwwroot/.python_packages/lib/site-packages/azureml/_project/ignore_file.py", line 6, in <module> import pathspec File "/home/site/wwwroot/.python_packages/lib/site-packages/pathspec/__init__.py", line 32, in <module> from .gitignore import ( File "/home/site/wwwroot/.python_packages/lib/site-packages/pathspec/gitignore.py", line 15, in <module> from .pathspec import ( File "/home/site/wwwroot/.python_packages/lib/site-packages/pathspec/pathspec.py", line 23, in <module> from . import util File "/home/site/wwwroot/.python_packages/lib/site-packages/pathspec/util.py", line 30, in <module> from .pattern import ( File "/home/site/wwwroot/.python_packages/lib/site-packages/pathspec/pattern.py", line 192, in <module> class RegexMatchResult(object): File "/home/site/wwwroot/.python_packages/lib/site-packages/dataclasses.py", line 950, in wrap return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen) File "/home/site/wwwroot/.python_packages/lib/site-packages/dataclasses.py", line 800, in _process_class cls_fields = [_get_field(cls, name, type) File "/home/site/wwwroot/.python_packages/lib/site-packages/dataclasses.py", line 800, in <listcomp> cls_fields = [_get_field(cls, name, type) File "/home/site/wwwroot/.python_packages/lib/site-packages/dataclasses.py", line 659, in _get_field if (_is_classvar(a_type, typing) File "/home/site/wwwroot/.python_packages/lib/site-packages/dataclasses.py", line 550, in _is_classvar return type(a_type) is typing._ClassVar

I tried changing different libraries, loading with pickle instead of joblib but the error was still the same


Solution

  • I managed to find a workaround. It seems like Azure has a problematic import path, thus wrong typing package is imported. Python 3.8 has the typing package built-in, but it's trying to use the obsolete one installed with pip, which is causing the problem.

    Add this at the very beginning of your file, before any imports:

    import sys
    sys.path = sorted(sys.path, key=lambda x: 'site-packages' in x)
    

    It essentially prioritizes built-in packages instead of ones installed with pip.