Repository: conan-io/conan

Issue:
conan 1.4.x fails when "scm" attribute in recipe is not a dict
Hi @lasote and @memsharded ,

at first of all thanks for implementing the first version of scm feature. Sadly I was unable to review it completely before the 1.4.0 release.

The current implementation fails (without changing our recipes) because we also have an "scm" attribute but which is an instance of our "private" SCM implementation.

The traceback is:

```
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/conan-1.4.2-py2.7.egg/conans/client/command.py", line 1182, in run
    method(args[0][1:])
  File "/usr/local/lib/python2.7/dist-packages/conan-1.4.2-py2.7.egg/conans/client/command.py", line 246, in create
    test_build_folder=args.test_build_folder)
  File "/usr/local/lib/python2.7/dist-packages/conan-1.4.2-py2.7.egg/conans/client/conan_api.py", line 77, in wrapper
    return f(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/conan-1.4.2-py2.7.egg/conans/client/conan_api.py", line 310, in create
    self._user_io.out, self._client_cache)
  File "/usr/local/lib/python2.7/dist-packages/conan-1.4.2-py2.7.egg/conans/client/cmd/export.py", line 61, in cmd_export
    _export_conanfile(conanfile_path, output, client_cache, conanfile, conan_ref, keep_source)
  File "/usr/local/lib/python2.7/dist-packages/conan-1.4.2-py2.7.egg/conans/client/cmd/export.py", line 136, in _export_conanfile
    output, paths, conan_ref)
  File "/usr/local/lib/python2.7/dist-packages/conan-1.4.2-py2.7.egg/conans/client/cmd/export.py", line 107, in _capture_export_scm_data
    scm = get_scm(conanfile, src_path)
  File "/usr/local/lib/python2.7/dist-packages/conan-1.4.2-py2.7.egg/conans/client/source.py", line 18, in get_scm
    return SCM(data, src_folder)
  File "/usr/local/lib/python2.7/dist-packages/conan-1.4.2-py2.7.egg/conans/model/scm.py", line 13, in __init__
    self.type = data.get("type")
AttributeError: 'property' object has no attribute 'get'
```

The reason is that there is no dict instance check implemented in `get_scm()` but IMHO it has to. Something like the following should be enough:

```
def get_scm(conanfile, src_folder):
    data = getattr(conanfile, "scm", None)
    if data is not None and isinstance(data, dict):
        return SCM(data, src_folder)
    else:
        # not an instance of dict or None, skip SCM feature.
        pass
```

Would be nice if you can fix this as soon as possible.

Thanks in advance.
Best Aalmann


---
To help us debug your issue please explain:

- [x ] I've read the [CONTRIBUTING guide](https://raw.githubusercontent.com/conan-io/conan/develop/.github/CONTRIBUTING.md).
- [ x] I've specified the Conan version, operating system version and any tool that can be relevant.
- [ x] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.



Discussion:
Wow. hard issue. I'm wondering, what to do if someone had the `scm` attribute and it was a `dict`?
I think in that case it will break (because missing/wrong fields) but his complaining would be as legit as yours. And ignoring possible errors when you really don't know if the user wanted to use the `scm` feature or not is dangerous.
So probably the only thing we can do is cheking the type as you suggested, but will see if we have more issues. It is funny because we named it `scm` mostly because of your suggestion ;).
WDYT @memsharded ? 
@lasote my suggestion was `scm_details` :smirk: (see #2643)

How ever, you are right, it is not easy to guess the users intention of his `scm` attribute. The easiest way is to raise the error (missing fields). This would break the build of some users which are using an scm dict for another use case (IMHO the risk is low). On the other hand, one could catch this exception, print an error and skip the SCM feature. But then you will not be able to catch and throw typos in scm dict (IMHO the risk is high).

Conclusion: Just checking for dict and throw an exception at missing fields should be sufficient enough. :smile: 

Resolving patch:
diff --git a/conans/client/source.py b/conans/client/source.py
--- a/conans/client/source.py
+++ b/conans/client/source.py
@@ -14,8 +14,11 @@
 
 def get_scm(conanfile, src_folder):
     data = getattr(conanfile, "scm", None)
-    if data is not None:
+    if data is not None and isinstance(data, dict):
         return SCM(data, src_folder)
+    else:
+        # not an instance of dict or None, skip SCM feature.
+        pass
 
 
 def complete_recipe_sources(remote_manager, client_cache, registry, conanfile, conan_reference):


Test patch:
diff --git a/conans/test/functional/scm_test.py b/conans/test/functional/scm_test.py
--- a/conans/test/functional/scm_test.py
+++ b/conans/test/functional/scm_test.py
@@ -40,6 +40,20 @@ def _commit_contents(self):
         self.client.runner("git add .", cwd=self.client.current_folder)
         self.client.runner('git commit -m  "commiting"', cwd=self.client.current_folder)
 
+    def test_scm_other_type_ignored(self):
+        conanfile = '''
+from conans import ConanFile, tools
+
+class ConanLib(ConanFile):
+    name = "lib"
+    version = "0.1"
+    scm = ["Other stuff"]
+
+'''
+        self.client.save({"conanfile.py": conanfile})
+        # nothing breaks
+        self.client.run("export . user/channel")
+
     def test_repeat_clone_changing_subfolder(self):
         tmp = '''
 from conans import ConanFile, tools