Repository: beetbox/beets

Issue:
Deprecation warning in plugins.py
### Problem

Installed beets from fedora repo and getting the following error every time I run any command

Running this command in verbose (`-vv`) mode:

```sh
[akya@quady scripts] $ beet -vv
user configuration: /home/akya/.config/beets/config.yaml
data directory: /home/akya/.config/beets
plugin paths: /home/akya/.config/beets/beetsplug
/usr/lib/python3.6/site-packages/urllib3/contrib/pyopenssl.py:46: DeprecationWarning: OpenSSL.rand is deprecated - you should use os.urandom instead
  import OpenSSL.SSL
Sending event: pluginload
/usr/lib/python3.6/site-packages/beets/plugins.py:114: DeprecationWarning: inspect.getargspec() is deprecated, use inspect.signature() or inspect.getfullargspec()
  argspec = inspect.getargspec(func)
lyrics: Disabling google source: no API key configured.
library database: /home/akya/data/musiclibrary.db
library directory: /media/Media/Songs/English
Sending event: library_opened
Usage: 
  beet COMMAND [ARGS...]
  beet help COMMAND

Options:
  --format-item=FORMAT_ITEM
                        print with custom format
  --format-album=FORMAT_ALBUM
                        print with custom format
  -l LIBRARY, --library=LIBRARY
                        library database file to use
  -d DIRECTORY, --directory=DIRECTORY
                        destination music directory
  -v, --verbose         log more details (use twice for even more)
  -c CONFIG, --config=CONFIG
                        path to configuration file
  -h, --help            show this help message and exit

Commands:
  bad               check for corrupt or missing files
  clearart          remove images from file metadata
  config            show or edit the user configuration
  convert           convert to external location
  duplicates (dup)  List duplicate tracks or albums.
  embedart          embed image files into file metadata
  extractart        extract an image from file metadata
  fetchart          download album art
  fields            show fields available for queries and format strings
  help (?)          give detailed help on a specific sub-command
  import (imp, im)  import new music
  info              show file metadata
  lastgenre         fetch genres
  list (ls)         query the library
  lyrics            fetch song lyrics
  missing (miss)    List missing tracks.
  modify (mod)      change metadata fields
  move (mv)         move or copy items
  play              send music to a player as a playlist
  remove (rm)       remove matching items from the library
  splupdate         update the smart playlists. Playlist names may be passed
                    as arguments.
  stats             show statistics about the library or a query
  update (upd, up)  update the library
  version           output version information
  web               start a Web interface
  write             write tag information to files
Sending event: cli_exit

```

Led to this problem:

```
[akya@quady scripts] $ beet --version
/usr/lib/python3.6/site-packages/urllib3/contrib/pyopenssl.py:46: DeprecationWarning: OpenSSL.rand is deprecated - you should use os.urandom instead
  import OpenSSL.SSL
/usr/lib/python3.6/site-packages/beets/plugins.py:114: DeprecationWarning: inspect.getargspec() is deprecated, use inspect.signature() or inspect.getfullargspec()
  argspec = inspect.getargspec(func)
beets version 1.4.6
Python version 3.6.4
plugins: badfiles, beatport, convert, duplicates, embedart, fetchart, info, lastgenre, lyrics, missing, mpdupdate, play, smartplaylist, web

```

Here's a link to the music files that trigger the bug (if relevant): 


### Setup

* OS: Fedora 27
* Python version: 3.6.4 
* beets version: 1.4.6
* Turning off plugins made problem go away (yes/no): yes, problem is in plugins.py

My configuration (output of `beet config`) is:

```yaml
directory: /media/Media/Songs/English
#directory: /media/Media/Songs/Hindi
library: ~/data/musiclibrary.db
#library: ~/data/musiclibrary2.db
import:
    copy: no
    write: yes
    log: /home/akya/.config/beets/import.log

pluginpath: 
    - /home/akya/.config/beets/beetsplug/

plugins: fetchart embedart lastgenre lyrics web missing beatport duplicates convert info play smartplaylist mpdupdate badfiles

play:
    command: mpv $args --playlist

mpd:
    host: 192.168.1.100
    port: 6600

fetchart:
    cautious: true
    cover_names: front back
    minwidth: 300
    sources: itunes *

smartplaylist:
    relative_to: 
    playlist_dir: ~/.mpd/playlists
    playlists:
        - name: fav.m3u
          query: 'comments:Fav'
        - name: new.m3u
          query: 'comments:New'
        - name: epic.m3u
          query: 'comments:Epic'
        - name: lush.m3u
          query: 'comments:Lush'
        - name: naruto.m3u
          query: 'comments:Naruto'
        - name: latest.m3u
          query: 'added:2017-11-27'
convert:
    format: mp3
    dest: /home/akya/1Dump/sync
    max_bitrate: 320
    never_convert_lossy_files: yes


paths:
    default: $albumartist/$album%aunique{}/$track $title
#    default: $album%aunique{}/$track $title
    singleton: Non-Album/$artist - $title
    comp: Compilations/$album%aunique{}/$track $title

```



Discussion:
Hi! That’s interesting—thanks for reporting. Do you know why you might be seeing this while other users (like myself) on 3.6 don’t? Is this a brand-new deprecation in a point release, or is this somehow a Debian-related thing?
Earlier I was using beets from pip.. It was 1.4.5 I think, but then I saw that beets was available in dnf, I removed the one from pip and installed from DNF.. Since then I am seeing this.. If I remove the plugins in the config, I don't see any error.
Thanks. Looks like we need an updated call akin to this change: https://github.com/praw-dev/praw/pull/551/files#diff-2a573d21bf9c7db67d16b42ba4e8193eR37
I can't remember exactly when it started, but I got this `DeprecationWarning` on Fedora 27 for quite a while. The error remains after upgrade to Fedora 28.

- beet version (installed from Fedora repository:
```
$ beet --version
/usr/lib/python3.6/site-packages/beets/plugins.py:114: DeprecationWarning: inspect.getargspec() is deprecated, use inspect.signature() or inspect.getfullargspec()
  argspec = inspect.getargspec(func)
beets version 1.4.6
Python version 3.6.5
plugins: embedart, fetchart, info, lyrics
$ 
```
- Fedora release
```
$ lsb_release -a
LSB Version:    :core-4.1-amd64:core-4.1-noarch
Distributor ID: Fedora
Description:    Fedora release 28 (Twenty Eight)
Release:        28
Codename:       TwentyEight
$ 
```
- python versions
```
$ python --version
Python 2.7.15
$ python3 --version
Python 3.6.5
```

Same here: Fedora 29, beets 1.4.7
On running beets I get these warnings:
```
/usr/lib/python3.7/site-packages/socks.py:58: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3
.8 it will stop working                   
  from collections import Callable    
/usr/lib/python3.7/site-packages/beets/plugins.py:130: DeprecationWarning: inspect.getargspec() is deprecated, use inspect.signature() or inspect.getfullargspec()
  argspec = inspect.getargspec(func)              
/usr/lib64/python3.7/site-packages/yaml/constructor.py:126: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprec
ated, and in 3.8 it will stop working     
  if not isinstance(key, collections.Hashable):
```

Otherwise functions normally. Same behavior from repository package and pip install :-(
Strange that this seems to occur on some distros but not others.

The last one, at least, should be fairly straightforward to fix if anyone's interested in lending a hand!
It must be that Fedora's Python build has some debug flags on that help catch stuff like this. Anyways a simple change of `inspect.getargspec()` with `inspect.getfullargspec()` is all is needed for PY3 to stop complaining. It would break beets on PY2 though.

Edit: or, sth like this:
```diff
diff --git a/beets/plugins.py b/beets/plugins.py
index 6dec7ef2..c26b1034 100644
--- a/beets/plugins.py
+++ b/beets/plugins.py
@@ -20,6 +20,7 @@ from __future__ import division, absolute_import, print_function
 import inspect
 import traceback
 import re
+import sys
 from collections import defaultdict
 from functools import wraps
 
@@ -127,7 +128,10 @@ class BeetsPlugin(object):
         value after the function returns). Also determines which params may not
         be sent for backwards-compatibility.
         """
-        argspec = inspect.getargspec(func)
+        if sys.version_info[0] < 3:
+            argspec = inspect.getargspec(func)
+        else:
+            argspec = inspect.getfullargspec(func)
 
         @wraps(func)
         def wrapper(*args, **kwargs):
``` 

Still more stuff to clean afterwards on the way to PY3 only though...
We also have six as a dependency, so `if six.PY2:` could be a little simpler.
Well, no need for superfluous imports then:
```diff
diff --git a/beets/plugins.py b/beets/plugins.py
index 6dec7ef2..69784d26 100644
--- a/beets/plugins.py
+++ b/beets/plugins.py
@@ -127,7 +127,10 @@ class BeetsPlugin(object):
         value after the function returns). Also determines which params may not
         be sent for backwards-compatibility.
         """
-        argspec = inspect.getargspec(func)
+        if six.PY2:
+            argspec = inspect.getargspec(func)
+        else:
+            argspec = inspect.getfullargspec(func)
 
         @wraps(func)
         def wrapper(*args, **kwargs):
```
Awesome. Would you mind opening a pull request with that patch?

Resolving patch:
diff --git a/beets/plugins.py b/beets/plugins.py
--- a/beets/plugins.py
+++ b/beets/plugins.py
@@ -17,7 +17,6 @@
 
 from __future__ import division, absolute_import, print_function
 
-import inspect
 import traceback
 import re
 from collections import defaultdict
@@ -27,6 +26,7 @@
 import beets
 from beets import logging
 from beets import mediafile
+from beets.util import inspect
 import six
 
 PLUGIN_NAMESPACE = 'beetsplug'
diff --git a/beets/util/inspect.py b/beets/util/inspect.py
new file mode 100644
--- /dev/null
+++ b/beets/util/inspect.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+# This file is part of beets.
+# Copyright 2019, Vladimir Zhelezov.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+from __future__ import absolute_import
+
+import inspect
+from collections import namedtuple
+
+from six import PY2
+
+
+ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
+
+
+def getargspec(func):
+    if PY2:
+        return inspect.getargspec(func)
+
+    sig = inspect.signature(func)
+    args = [
+        p.name for p in sig.parameters.values()
+        if p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD
+    ]
+    varargs = [
+        p.name for p in sig.parameters.values()
+        if p.kind == inspect.Parameter.VAR_POSITIONAL
+    ]
+    varargs = varargs[0] if varargs else None
+    varkw = [
+        p.name for p in sig.parameters.values()
+        if p.kind == inspect.Parameter.VAR_KEYWORD
+    ]
+    varkw = varkw[0] if varkw else None
+    defaults = tuple(p.default for p in sig.parameters.values()
+                     if p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD
+                     and p.default is not p.empty) or None
+
+    return ArgSpec(args, varargs, varkw, defaults)


Test patch: