Add
* Added tests for “clu.naming.dotpath_to_prefix(…)” [Alexander Böhn]
* Added argument checking to “clu.naming.dotpath_to_prefix(…)” [Alexander Böhn]
* Added φ to represent the name of a Partial lambda-type ... which, you may ask, what the fuck does that mean? Allow me to explain: I had originally used a hack (by way of subclassing) to allow the Partial types returned from “apply_to(…)” to be given names and repr-string that matched lambda-type functions – that is to say, functions created with the “lambda” keyword – and in doing so, they’d all be treated the same as lambda-types by the “clu.exporting” mechanisms. This was handy because, as it turned out, “apply_to(…)” Partials were just as useful as typical lambda-type predicates, in like a whooole lot of the kinds of situations we get ourselves into, programmatically, here in the salt-mines of CLU coding. ... The problem arose just now, which while checking out some other recent (but unrelated) updates to the Partial-type structure, I saw that Partial instances retained a value for “__module__” that matched where the Partial class was defined (that is to say, “clu.predicates”) rather than wherever that specific Partial had been instantiated. ... I did not like that. This was due, of course, to the fact that lambda-types are created with a keyword, whereas Partial-types are just dumb ol’ instances, and these things obey different internal Python laws. ... To fix it, the Exporter again came to the rescue. This patch is mainly: a) The addition of the constant φ to represent the default name of the Partial-type – known as the “phi-type” here- after – and all the necessary support for a constant of this sort (it gets referenced in some GREEK_STUFF dict somewhere, etc etc). b) The embellishment of the Exporter’s “export” method to support the φ constant and the phi-type idea – which incedentally results in the “__lambda_name__” attribute actually being useful now, as it retains the naming information germane to what the thing originally was: lambda-type (“<lambda>”) or phi-type (“<Partial>”). c) The necessary tweaks to related functions to consider all of this (like e.g. the clu.typology predicate called “islambda(…)” considers both λ and φ when checking the value of “__lambda_name__”) d) Finally, and most crucially, the addition of logic – again in the Exporter – to alter the attribute value of “__module__” to the correct value whenever it encounters a phi-type in need of name-adjustment. This is doubly interesting (if you asked me) as it is the first use of the “dotpath” attribute the Exporter now sets, as a result of that recent edit wherein all Exporters are now initialized as “Exporter(path=__file__)” – the “path” value is used to compute the dotted module path, and lo, IT SEEMS TO WORK!!!!!!!!!!!!!!! Yeah dogg. [Alexander Böhn]
* Adding the new Directory subclasses to the REPL environment. [Alexander Böhn]
* Added two more Directory shortcut-subclasses in “clu.fs.filesystem” [Alexander Böhn]
* Added “predicate_none(…)” to clu.predicates using “negate(…)” ... also added tests for same and for the recently-added predicate “clu.typology.differentlength(…)” [Alexander Böhn]
* Added “differentlength” to clu.predicates ... this predicate isn’t a simple “negate(…)” of “samelength(…)” – it checks that its arguments are iterable in the same way as “samelength(…)” – so we define it here preemptively because of the fact that its negation is nontrivial. [Alexander Böhn]
* Added scripts/show-consts.py – a prettyprinter for clu.constants ... It’s adapted from the ad-hoc little inline const prettyprinter, “clu.constants.consts.print_all()” with a bunch of my own ANSI formatting sludge on top ... At this point it looks childish, but not too far off the final mark – it’s a weird medium in which to design, can I just say? ... Yeah like I would say 72-74% done, maybe ... Just go ahead, straight up `python scripts/show-consts.py` to execute it… you (meaning anyone besides me) might have to do some freaky PYTHONPATH shit first; I am virtualenv-ing all of this stuff right now but I’ll try and make these sort of things work OK, as like a example-code thing, an “Intro to CLU” type of deal, maybe. [Alexander Böhn]
* Added and filled a fixture graveyard at tests/obsolete_fixtures.py ... contains my spruced-up versions of the pytest-datadir fixture code, like for future reference of someshit I guess. [Alexander Böhn]
* Added a test for “resolve(…)” from clu.predicates. [Alexander Böhn]
* Added in instance checks for “metaclass(…)” tests. [Alexander Böhn]
* Added “iscallable(…)” and “iscallablelist(…)” to clu.typology ... and in so doing also tweaked “isfunction(…)” to return False for class types – all of which are callable – and any arbitrary instances of class types in posession of a `__call__(…)` method …the identification of which is now the domain of the brand-new “iscallable(…)” predicate. NOTE that this means “iscallable(…)” is VERRRRY DIFFERENT from the builtin “callable(…)” predicate, the likes of which is very eager call its operands callable if that is in any way vaguely the case. [Alexander Böhn]
* Adding to the “callable_types” typelist in clu.typology. [Alexander Böhn]
* Added a test for the collator-based accessors. [Alexander Böhn]
* Added “metaclass(…)” predicate and collator-based accessors ... all are found in clu.predicates; ... `metaclass(thing)` will retrieve either a) type(type(thing), b) type(thing), or c) thing, depending on whether “thing” is a metaclass, a class, or an instance. ... There are three new accessors: “attrs(…)”, “pyattrs(…)” and “items(…)”. These are all based on the new “collator(…)” apply- style basis function, which works like the “accessor(…)” and “searcher(…)” functions to apply one simple “getattr(…)”-type function to a thing, using a list of 1+ attribute or item names to compose its result. Unlike the other functions, which return the first viable result from the application list that gets returned, “collator(…)”-based accessors accumulate all results into an ordered tuple for return. WHICH MEANS: these accessors work like so: [Alexander Böhn]
class YoDogg(object):
yo = "Yo dogg,"
dogg = "I heard you like"
iheard = "irritating recursion"
assert attrs(YoDogg, 'yo', 'dogg') == ("Yo Dogg,",
"I heard you like")
assert attrs(YoDogg, 'dogg', 'yo') == ("I heard you like",
"Yo Dogg,")
assert attrs(YoDogg, 'yo', 'wtf') == ("Yo Dogg,",)
assert attrs(YoDogg, 'wtf', 'hax') == None
... I mean and you know the drill by now, “pyattrs(…)” is the same
shit but for __python__ __reserved__ __names__, and “items(…)”
of course is for getting items, like out of dicts and whatnot.
Minutiae
* Minutiae. [Alexander Böhn]
Other
* Bump version: 0.1.6 → 0.1.7. [Alexander Böhn]
* Tests for “clu.exporting.Exporter” instance registry. [Alexander Böhn]
* If a module wasn’t using the Exporter just then, it is now. [Alexander Böhn]
* Instance registry for all “clu.exporting.Exporter” objects. [Alexander Böhn]
* REPL script updates. [Alexander Böhn]
* Combined “path_to_dotpath(…)” and “dotpath_to_prefix(…)” ... and what do we get? why, “path_to_prefix(…)” of course, you doofus goober! ... threw in some quick addenda to the “dotpath_to_prefix(…)” test function to test this new shortcut. [Alexander Böhn]
* Trimmed dead code. [Alexander Böhn]
* F-STRINGS!!! F-STRINGS!!!!!!!!! F-STRINGS!!!!!!!!!!!!!! [Alexander Böhn]
* Rewrote “clu.predicates.getitem(…)” to not use a ‘get()’ function ... now it sticks to basic “__getitem__(…)” and “__contains__(…)” calls, which are fine ... also: started generally replacing the string-interpolate ‘%’ operator with f-strings (yay!!!!!) [Alexander Böhn]
* That empty-string default to “getattr(…)” was bugging me ... in “clu.exporting.Exporter.export(…)”, so I changed it up. [Alexander Böhn]
* Streamlining in the “clu.exporting.Exporter” initializer. [Alexander Böhn]
* Realigning “clu.exporting.Exporter” logic. [Alexander Böhn]
* Allow easy access to a Partial’s function and predicate arguments ... that is, “clu.predicates.Partial”, our custom module-local subclass of “functools.partial” that we use with “apply_to(…)” ... this “Partial” class is only ever returned from “apply_to(…)”; as such, we can kit it out for that purpose – as in this case, where we’ve added some properties for accessing the “function” and “predicate” arguments that were used to initialize this Partial instance. [Alexander Böhn]
* Ensure that copy operations in “clu.fs.filesystem” return booleans. [Alexander Böhn]
* Further simplifying the sequence predicates of “clu.typology” ... instead of manually checking the sequence argument in a lambda definition, we make all of the simple sequence predicates the partial-application result of “predicate_all(predicate)” which basically delegates the sequence argument handling to the “apply_to(…)” internals, which are like way more considerate than any ad-hoc stuff could possibly manage to be ... still, also added “isxtypelist(…)” intermediate (even though there was only one sequence-predicate corner-case that used a call to “istypelist(…)” rather than “issequence(…)” and that has since been redefined using the “predicate_all(…)” trick mentioned above, it’s helpful to look at if you’re thinking about doing something of that sort ... Yeah! Basically. [Alexander Böhn]
* Using an intermediate predicate to simplify the sequence predicates ... that are found in “clu.typology” ... added a “xlist(predicate, thinglist)” lambda, which basically is a shortcut for: [Alexander Böhn]
issequence(thinglist) and predicate_all(predicate, thinglist)
… which was getting to be a boilerplate-y repetetive refrain in
all of those “clu.typology” sequence predicates
... used this new intermediate in “clu.mathematics” just basically
to like kick the tires and soforth
* Simplified “lambda_repr(…)” definition in clu.predicates ... the “pyname(…)” shortcut lambda had been defined, like, a mere eleven LoC north of the offending definition… how embarrasing. [Alexander Böhn]
* Simplified the “predicate_none” test predicate. [Alexander Böhn]
* Importing “operator” in reply-bpython.py. [Alexander Böhn]
* Updated “clu.typology” testsuite function name. [Alexander Böhn]
* Fixed test function name, which was wrong, and needed fixing. [Alexander Böhn]
* Updated some filesystem tests to use the “temporarydir” fixture. [Alexander Böhn]
* Moved the huge greek-text dict to new module “clu.constants.data” ... Which OK yeah I know “data” is a lame-ass name for a module or anything like that – technically they *all* contain data so it is not that descriptive – but I wanted a catch-all junk-drawer module, and so. Yes! [Alexander Böhn]
* Removed dangling import. [Alexander Böhn]
* Trying package scope for the “dirname” fixture ... the latest pytest docs call package-scope “experimental” – so that’s what this is: like that time you drunkenly made out with your sophomore-year roommate and then never really talked about it afterward for like twenty years, I am “experimenting”. [Alexander Böhn]
* Split the “datadir” fixture into two fixtures, one module-scoped ... this way a) you can just get the "test/data" path wrapped in a Directory instance, if you like, and b) that part of all the fixture code only runs once per module, which that in theory might be vaguely faster, one day. [Alexander Böhn]
* Sometimes you have to just do it yourself to do it right ... I mean, no offense to the pytest-datadir author(s), or to the people behind pytest itself – but what the fuck, the datadir plugin has, you know, ONE JOB: mirror a data directory for use at test-function scope. And I mean, it was technically doing that job – but that’s all it was doing; its usage was causing copies of the mirrored directory contents to unceremoniously pile up in a $TMPDIR subfolder (hithertofore unknown to me) called “pytest-of-fish” (because that’s my local username, OK, “fish”)… like one copy every time the fucking testsuite ran. There are like a nontrivial stash of test images in there right now (and that is just like off the bat, it would only have gone up) and I was only using the fixture in like ONE fucking test, imagine had I been more zealous. ... So OK whatever, like I am sure all the other pytest programmers and plugin developers all have gigantic SANs and redundant SSDs in the biggest and storage-capacity-est laptops money can buy, or someshit – I do not, and after dealing with multitudinous secret stashes like e.g. “.pytest_cache” and “.tox” and others, I was not expecting this last heap of data to show up where it did, grow with reckless abandon until “rm -rf”-ed, without any further explanation. ... So! I looked at the fucking plugin and it was like 20 lines of code, in three fixture functions. I copypasta’ed it into clu’s “conftest.py” file, commented it (which like expanded its LoC count by at least 2.5x) and then wrote a new fixture that did what the original code was supposed to do – only a) correctly, b) using my own filesystem abstractions, which are fairly more featureful in a bunch of ways than “pathlib.Path” or othershit … «BRAGGGGG» yes erm ok – but and then c) using `yield` and managed context and assertions, because who the fuck wrote this original shit anyway?? I am sorry guys but your thing had ONE FUCKING JOB and while it technically did do this (like, without shooting uncaught exceptions everywhere or trashing my files, I guess) IT SUCKED. My shit rules, because it works, it’s legible, it’s commented and be-docstring’d and on GitHub – any one can use it of course – and it doesn’t have the ridiculous overblown sense of purpose to be like a whole plugin package and shit. YOURE JUST ANOTHER PART OF ME!! oh wait I shouldn’t be quoting that guy these days, how uncouth, sorry about that. [Alexander Böhn]
* Replaced “allof(…)” helper with “and” operator expressions ... the problem with using “allof(…)” within functional-style compositions is that it does not short-circuit, so you can’t really use it in situations like: [Alexander Böhn]
yodogg = lambda a, b: allof(isiterable(a),
isiterable(b),
set(a).issuperset(set(b)))
… which that looks like it might work, but if either “a” or “b”
is actually not iterable – that is to say, one of the first two
predicates being fed to “allof(…)” evaluates to False – then
the last expression throws a TypeError at the point where it
attempts to initialize a `set` with something non-iterable.
… This lambda should be rewritten like this:
yodogg = lambda a, b: isiterable(a) and \
isiterable(b) and \
set(a).issuperset(set(b))
… Notice how all it takes is a backslash and some indentation
here and there, and no one has to gripe about “waaaah Python
lambdas’re only one line, whyyyyyy” or such shit. Yeah so the
2nd form of the lambda works if you call “yodogg(None, None)” –
that is, assuming returing False from such a call is within the
definition of “works”. Frankly if you *want* exceptions (which
generally I don’t, for normal operations) that is one case in
which lambdas will definitely not assuage your issues, as you
can’t really backslash your way through try/except blocks, I
don’t think. Yep.
... Also in this commit: some miscellaneous import-juggling
* Minor simplification in the clu.exporting.Exporter constructor. [Alexander Böhn]
* Whitespace OCD. [Alexander Böhn]
* Simplified some of the collator tests’ assertions. [Alexander Böhn]
* Renamed “collator” to “acquirer” and rewrote “collator” ... as always this is all found in clu.predicates, my favorite module these days ... “collator” better refered to the operation that got all of the occurrences of something* across all of a list of things (as it is now), rather than the operation to get each occurrence of many somethings from a single thing (which is what “acquirer” now does); I like these names better as they are more apropos, what do you think? [Alexander Böhn]
* Got rid of “unicode” usage in clu.predicates. [Alexander Böhn]
* Exporting some oddly un-exported typelists from clu.typology. [Alexander Böhn]
* Test for “isunique(…)” and “samelength(…)” of clu.typology. [Alexander Böhn]
* I dunno dogg it just reads better this way I think. [Alexander Böhn]
* Rewrote “isunique(¬)” and added “samelength(¬)” in clu.typology. [Alexander Böhn]
* Import ordering OCD. [Alexander Böhn]
* Expanded “apply_to(…)” test to include exception-raising. [Alexander Böhn]
* Amended test function name. [Alexander Böhn]
* Tests for “subclasscheck(…)” and sundry callable-related predicates ... all from clu.typology, in the new typology test suite. [Alexander Böhn]
* Formatting and whitespace. [Alexander Böhn]
* Removed unnecessary call to “maketypelist(…)” in “subclasscheck(…)” ... that would be in clu.typology – in the function definition that is arguably the backbone of that whole module, actually. [Alexander Böhn]
* Finally, started a testcase suite for clu.typology. [Alexander Böhn]
* Trepidaciously starting to use “functools.wraps(…)” in “negate(…)” ... I can’t seem to get it to NOT update the function signature, as is displayed in e.g. bpython above the display of inline __doc__ strings …!? [Alexander Böhn]
* Expanded classtype predicates test to cover “metaclass(…)” [Alexander Böhn]
* Fixed a docstring that was showing the wrong arity. [Alexander Böhn]
* Made “isfunction(…)” – née “ΛΛ(…)” – not use “callable(…)” [Alexander Böhn]
* Using an empty tuple as the collator’s default return value. [Alexander Böhn]
* Exporting “collator(…)” from clu.predicates. [Alexander Böhn]
* Using new collation accessor to build typelists in clu.typology. [Alexander Böhn]
* Whitespace. [Alexander Böhn]
* Fixed SUNDER and DUNDER in clu.enums. [Alexander Böhn]
Whoooooooooops
* Updated an old source notation in clu.typology. [Alexander Böhn]
* Swiped dotpath-attribute resolution function snipped from stdlib ... AND IT JUST WORKS. Tests just pass, everything is just fine. HOW IS THAT POSSIBLE… I am suspicious of course but if that were to be that, how awesome would that be??? Here’s the orig: [Alexander Böhn]
https://docs.python.org/3/library/operator.html#operator.attrgetter
... YEAH!!!