55ignores the external pytest-cache
66"""
77from __future__ import absolute_import , division , print_function
8-
98from collections import OrderedDict
109
1110import py
1211import six
12+ import attr
1313
1414import pytest
1515import json
16- import os
17- from os .path import sep as _sep , altsep as _altsep
18- from textwrap import dedent
16+ import shutil
17+
18+ from . import paths
19+ from .compat import _PY2 as PY2 , Path
20+
21+ README_CONTENT = u"""\
22+ # pytest cache directory #
23+
24+ This directory contains data from the pytest's cache plugin,
25+ which provides the `--lf` and `--ff` options, as well as the `cache` fixture.
26+
27+ **Do not** commit this to version control.
28+
29+ See [the docs](https://docs.pytest.org/en/latest/cache.html) for more information.
30+ """
1931
2032
33+ @attr .s
2134class Cache (object ):
2235
23- def __init__ (self , config ):
24- self .config = config
25- self ._cachedir = Cache .cache_dir_from_config (config )
26- self .trace = config .trace .root .get ("cache" )
27- if config .getoption ("cacheclear" ):
28- self .trace ("clearing cachedir" )
29- if self ._cachedir .check ():
30- self ._cachedir .remove ()
31- self ._cachedir .mkdir ()
36+ _cachedir = attr .ib (repr = False )
37+ _warn = attr .ib (repr = False )
38+
39+ @classmethod
40+ def for_config (cls , config ):
41+ cachedir = cls .cache_dir_from_config (config )
42+ if config .getoption ("cacheclear" ) and cachedir .exists ():
43+ shutil .rmtree (str (cachedir ))
44+ cachedir .mkdir ()
45+ return cls (cachedir , config .warn )
3246
3347 @staticmethod
3448 def cache_dir_from_config (config ):
35- cache_dir = config .getini ("cache_dir" )
36- cache_dir = os .path .expanduser (cache_dir )
37- cache_dir = os .path .expandvars (cache_dir )
38- if os .path .isabs (cache_dir ):
39- return py .path .local (cache_dir )
40- else :
41- return config .rootdir .join (cache_dir )
49+ return paths .resolve_from_str (config .getini ("cache_dir" ), config .rootdir )
50+
51+ def warn (self , fmt , ** args ):
52+ self ._warn (code = "I9" , message = fmt .format (** args ) if args else fmt )
4253
4354 def makedir (self , name ):
4455 """ return a directory path object with the given name. If the
@@ -50,12 +61,15 @@ def makedir(self, name):
5061 Make sure the name contains your plugin or application
5162 identifiers to prevent clashes with other cache users.
5263 """
53- if _sep in name or _altsep is not None and _altsep in name :
64+ name = Path (name )
65+ if len (name .parts ) > 1 :
5466 raise ValueError ("name is not allowed to contain path separators" )
55- return self ._cachedir .ensure_dir ("d" , name )
67+ res = self ._cachedir .joinpath ("d" , name )
68+ res .mkdir (exist_ok = True , parents = True )
69+ return py .path .local (res )
5670
5771 def _getvaluepath (self , key ):
58- return self ._cachedir .join ("v" , * key . split ( "/" ))
72+ return self ._cachedir .joinpath ("v" , Path ( key ))
5973
6074 def get (self , key , default ):
6175 """ return cached value for the given key. If no value
@@ -69,13 +83,11 @@ def get(self, key, default):
6983
7084 """
7185 path = self ._getvaluepath (key )
72- if path .check ():
73- try :
74- with path .open ("r" ) as f :
75- return json .load (f )
76- except ValueError :
77- self .trace ("cache-invalid at %s" % (path ,))
78- return default
86+ try :
87+ with path .open ("r" ) as f :
88+ return json .load (f )
89+ except (ValueError , IOError , OSError ):
90+ return default
7991
8092 def set (self , key , value ):
8193 """ save value for the given key.
@@ -88,42 +100,25 @@ def set(self, key, value):
88100 """
89101 path = self ._getvaluepath (key )
90102 try :
91- path .dirpath ().ensure_dir ()
92- except (py .error .EEXIST , py .error .EACCES ):
93- self .config .warn (
94- code = "I9" , message = "could not create cache path %s" % (path ,)
95- )
103+ path .parent .mkdir (exist_ok = True , parents = True )
104+ except (IOError , OSError ):
105+ self .warn ("could not create cache path {path}" , path = path )
96106 return
97107 try :
98- f = path .open ("w" )
99- except py .error .ENOTDIR :
100- self .config .warn (
101- code = "I9" , message = "cache could not write path %s" % (path ,)
102- )
108+ f = path .open ("wb" if PY2 else "w" )
109+ except (IOError , OSError ):
110+ self .warn ("cache could not write path {path}" , path = path )
103111 else :
104112 with f :
105- self .trace ("cache-write %s: %r" % (key , value ))
106113 json .dump (value , f , indent = 2 , sort_keys = True )
107114 self ._ensure_readme ()
108115
109116 def _ensure_readme (self ):
110117
111- content_readme = dedent (
112- """\
113- # pytest cache directory #
114-
115- This directory contains data from the pytest's cache plugin,
116- which provides the `--lf` and `--ff` options, as well as the `cache` fixture.
117-
118- **Do not** commit this to version control.
119-
120- See [the docs](https://docs.pytest.org/en/latest/cache.html) for more information.
121- """
122- )
123- if self ._cachedir .check (dir = True ):
124- readme_path = self ._cachedir .join ("README.md" )
125- if not readme_path .check (file = True ):
126- readme_path .write (content_readme )
118+ if self ._cachedir .is_dir ():
119+ readme_path = self ._cachedir / "README.md"
120+ if not readme_path .is_file ():
121+ readme_path .write_text (README_CONTENT )
127122
128123
129124class LFPlugin (object ):
@@ -297,7 +292,7 @@ def pytest_cmdline_main(config):
297292
298293@pytest .hookimpl (tryfirst = True )
299294def pytest_configure (config ):
300- config .cache = Cache (config )
295+ config .cache = Cache . for_config (config )
301296 config .pluginmanager .register (LFPlugin (config ), "lfplugin" )
302297 config .pluginmanager .register (NFPlugin (config ), "nfplugin" )
303298
@@ -320,41 +315,40 @@ def cache(request):
320315
321316def pytest_report_header (config ):
322317 if config .option .verbose :
323- relpath = py . path . local (). bestrelpath (config .cache . _cachedir )
324- return "cachedir: %s" % relpath
318+ relpath = config . cache . _cachedir . relative_to (config .rootdir )
319+ return "cachedir: {}" . format ( relpath )
325320
326321
327322def cacheshow (config , session ):
328- from pprint import pprint
323+ from pprint import pformat
329324
330325 tw = py .io .TerminalWriter ()
331326 tw .line ("cachedir: " + str (config .cache ._cachedir ))
332- if not config .cache ._cachedir .check ():
327+ if not config .cache ._cachedir .is_dir ():
333328 tw .line ("cache is empty" )
334329 return 0
335330 dummy = object ()
336331 basedir = config .cache ._cachedir
337- vdir = basedir . join ( "v" )
332+ vdir = basedir / "v"
338333 tw .sep ("-" , "cache values" )
339- for valpath in sorted (vdir .visit ( lambda x : x .isfile () )):
340- key = valpath .relto (vdir ). replace ( valpath . sep , "/" )
334+ for valpath in sorted (x for x in vdir .rglob ( "*" ) if x .is_file ( )):
335+ key = valpath .relative_to (vdir )
341336 val = config .cache .get (key , dummy )
342337 if val is dummy :
343338 tw .line ("%s contains unreadable content, " "will be ignored" % key )
344339 else :
345340 tw .line ("%s contains:" % key )
346- stream = py .io .TextIO ()
347- pprint (val , stream = stream )
348- for line in stream .getvalue ().splitlines ():
341+ for line in pformat (val ).splitlines ():
349342 tw .line (" " + line )
350343
351- ddir = basedir .join ("d" )
352- if ddir .isdir () and ddir .listdir ():
344+ ddir = basedir / "d"
345+ if ddir .is_dir ():
346+ contents = sorted (ddir .rglob ("*" ))
353347 tw .sep ("-" , "cache directories" )
354- for p in sorted ( basedir . join ( "d" ). visit ()) :
348+ for p in contents :
355349 # if p.check(dir=1):
356350 # print("%s/" % p.relto(basedir))
357- if p .isfile ():
358- key = p .relto (basedir )
359- tw .line ("%s is a file of length %d" % (key , p .size () ))
351+ if p .is_file ():
352+ key = p .relative_to (basedir )
353+ tw .line ("{} is a file of length {:d}" . format (key , p .stat (). st_size ))
360354 return 0
0 commit comments