Sublime Forum

Import __builtin__ for python in Sublime?

#1

The package claims it doesn’t exist, but it is the core for sublime-text… I’d like to add additional string object functions and the only way to do this without having to define EVERY string with MyString( ‘xxx’ ) is to import builtin, class MyString( str ):

_builtin.str = MyStr

I want to add functions which don’t exist such as SubString ( so I don’t have to use [ : ] which is awful and doesn’t always support what I need it to… and more…

0 Likes

#2

All plugins share a single runtime, so modifying builtin objects sounds like a bad idea to me.

6 Likes

#3

“There must be a better way.”

Maybe you could explain what you intend to achieve by essentially replacing the default str class (which I don’t even know whether it works as you expect it to, even if this did work), so we can give pointers at potential solutions?

0 Likes

#4

Not sure what your question is but if what you want to know is how to subclass a builtin python object like str you can just subclass it like:

class MyString(str):
    def substring(self, start, end):
        return self[start:end]

If your question is instead how to override the builtin types you can just override __builtins__ like:

__builtins__.str = MyString

Now, that said, I think overriding python builtin types is a really bad idea almost 99% of times, better to consider them as “atomic” objects.

Finally, let me disagree with you about your concept of [:] being awful, the slicing operator is wonderful and just the pythonic way to go.

In any case, I’m still unclear what your real question was… just hope the above tips would help somehow

2 Likes

#5

builtin doesn’t seem to exist - if I try importing it, it says it doesn’t exist. If I simply try setting builtin.str = MyString I get a similar error stating builtin doesn’t exist…

The reason I don’t like : is because it doesn’t have all of the functionality you’d expect with a SubString function as implemented in many other languages… You can do a few things, and yeah, it may be ok for that, but I want a full-featured SubString function which also doesn’t look ugly … ie is human readable…

I teach hundreds of students on a regular basis multiple languages and important skills in the field of software / game development - it’s more often than not easier to express the reasoning behind an algorithm if it is more human readable with appropriate calls than it is to just have a comment above each of the strange operators. And it’s easy to dive into the function and why it works when it comes clearly labeled. The way I code is by keeping repetitive code to an absolute minimum, and to replace tasks with helper functions which end up clearly labeled as to the task and then I assemble them to solve a problem - it’s a core element to programming… the ability to take a large problem and scale it into it’s component parts and create a solution out of them.

I’m not looking to replace any pre-existing functions, but I am looking to add functionality where it is missing… Anyone who knows me from some of my other work on other projects knows I am a stickler for retaining backwards compatibility meaning I will not change the functionality of something so that it won’t work for packages that have designed their code around it - in this case… this doesn’t really matter because I won’t be replacing any of the default functions - only creating a few new ones…

For instance, some I want to add make a lot of sense and I find it odd they don’t exist… str.reverse( ) looks a lot better than _text[ : : - 1 ] and the meaning behind it, especially to a beginner, is immediately known… Oh - you’re reconfiguring the string to output in reverse order… instead of looking at _text[ : : - 1 ] and immediately believing that you’ll never understand what the hell this does… That’s another large aspect of teaching - if students are able to immediately make progress and immediately understand something then they are far more likely to stick with the learning of the language, and even progress to others - or take a much more heightened interest in the subject matter… - It’s not about making the material ‘easy’, it’s about presenting it in a way which conveys confidence to those learning it… So, in the beginning they can look at the building blocks and create things from that, and as they progress into the language they learn exactly what is pulling the strings behind the curtain…

Everything I code, I code to be as optimized as possible and as user-friendly to read as possible because I use a large portion of my creations as teaching material… And it is possible to create advanced software / games and present it in a way that almost anyone will be able to understand what is happening right away and as they progress they can peel back the layers to see how and why…

0 Likes

#6

Yes, but overriding __builtin__ is still bad, regardless of reasons. I know JavaScript has people doing things like prototypes, but this is just not Pythonic, and I’d argue not very cool to every other Python library.

So you override str in builtin and make all your slicing pretty. No other module wanted you to monkey patch str, but now they have to use your implementations regardless.

What you could do is put your modified str class in a module and then import it in only your libraries. So you create some file, we’ll call it utility.py with your special str implementation called mystr. In your modules, just import from utility.py improt mystr as str. Now you can use str without forcing every other library to adopt your opinion. So here you get exactly what you want without modifying builitin.

2 Likes

#7

Patching builtins is inherently dangerous. What if a newer version of Python includes a str.reverse method? What if another package patches builtins in an incompatible way? Your approach only works if no one else does it.

There’s nothing stopping you from creating a reverse function to use in your own code. But modifying builtins affects everyone else’s code.

2 Likes

#8

Some reading on builtins and how they are designed to be used

0 Likes

#9

I keep getting 500 error on post which is why this response has taken a lot of time…

@facelessuser - You’re right - As it is loaded into memory, yes my implementation would override the default and other modules would use the new implementation, however as the effects of an additional function would be negligible it wouldn’t bother or affect the object in any way which is noticeable… as I understand it, many languages strive to be as optimized as possible. This means, and I know this is true for Java, that when you extend an object, create a new one, etc… the data is only loaded once and only the data which changes is actually saved… Any time there is a duplicate of something, that duplicate is simply stored as the originals memory address until it changes.

It would be wrong of me to assume this is true for Python without doing additional research which I am happy to do. If it is the case then the difference between my additions would be incredibly small and no object actually doing anything with the function until it is used and each object would only save their string and not the functions as a copy… If I were designing a language, I’d do something similar because I prefer to be efficient and not requiring classes to be completely copied to each and every instance would mean memory use would free-fall… I’d like to think the Python creators did this, but again - I’ll do the research.

I tried numerous ways to override str ( and it may actually be _ _ builtins _ _ and not _ _ builtin _ _ ) and ran into wall after wall… I believe I tried the import method you’re suggesting as well with no luck, I also tried an @update method, etc… Just in case I didn’t, I will try it again.

I just tried it, and as I thought it doesn’t override str for my package, or any other…

Using a simply MyString class, from Package import MyString as str — ‘Test’.reverse( ) — str as no attribute reverse…
builtins doesn’t exist, builtin doesn’t exist… etc…

@ThomSmith - It isn’t dangerous if you are familiar enough with the language and the rules defined by the language… in addition to how it operates… If a future version includes reverse( ) my reverse( ) would still work unless they fundamentally change how [ : ] operates which is unlikely unless a MAJOR version change comes, and still it is very unlikely because it’d break many many scripts… When replacing or changing such a huge feature, popular languages give businesses a lot of time and a head start to update - but again… it’s incredibly unlikely this will happen because businesses that rely on Python may instead of updating their version of Python remain back, and if there is a security flaw this is a huge problem… another reason why languages tend to remain the same…

Additionally, if a future version creates version - as I said it wouldn’t affect mine - but I could then remove mine from my string library, or add it differently - for example similar to how I add AccessorFuncs - on initialization of the package itself, I could check to see if str.reverse exists and if it does then I don’t create it…

If someone else updates String, it would still work regardless of who replaces it first… If my package runs first and replaces str with mine - then another package loads and replaces str ( which is now mine ) then they simply extend mine which extends str… It works in reverse order too… That’s the point of inheritance…

If someone else adds a reverse function, the rules would be the same and they should both be backwards compatible but only one would be active, whichever replaces str last… reverse is a simple example of a function though and while there are many ways to do it - some slower / more costly to run than others - the end result would be the same so it’d still work.

I do understand all of the arguments against, but I have a lot of experience with this in dozens of other languages. I know how to make these backwards compatible if I replace an existing function ( which is NOT what I am doing here ), or if I create new functions then I’d follow the naming conventions of the language so everything operates naturally, and if the language adds the function then all I have to do is disable mine but I would design them to be as identical to the way the language would add them as possible. Heck, I typically even submit my implementations for approval to give a greater chance of them being accepted. I also teach how to properly reroute, update, add, etc… without interfering in the language because that’s something else I teach - how to properly match the standards of languages a company uses to keep the code as professional as possible as that’s something incredibly important when businesses hire someone to develop for them… Otherwise code would take way too long to maintain and the business would lose money in addition to looking incredibly unprofessional ( if the company ever sells itself and the buyer ends up getting a rats-nest then it’s typically less expensive to either outsource to rewrite from scratch or in-source to rewrite - reformatting code takes a long time ).

The problem with not being able to update built in objects means instead of simply being able to run ‘Testing’.reverse( ), you have to run MyStringClass( ‘Testing’ ).reverse( ) which takes much longer to write - it also means that existing code would need ALL of it’s strings to be altered in order to use the new object. It also makes the size of the file much larger and it goes against one of my rules - don’t repeat code which isn’t, or shouldn’t be necessary… This is to increase efficiency…

I understand why it may be frowned upon because it means anyone could simply start adding hundreds of functions which aren’t necessary or end up doing the same thing other functions already do - but if you do the proper amount of research and know how the developers add new features, how they’re most likely going to implement something, or to use it as a tool to get more interested in developing by building confidence because the code is easier to understand right away, the proper standards are used when adding the new functions, etc… then there’s no problem.

Here’s basically what happens…

# My File - without comments, etc...
class MyString( str ):
	def reverse( self ):
		return self[ : : - 1 ]

__builtin__.str = MyString

now str is MyString which extends str by adding reverse to it… 1 function… Now, if someone else wants to update str, since str returns builtin.str they will extend MyString… so they do:

# them
TheirString( str ):
	# Removes a chunk from a string starting at _index and removing _len chars...
	def snip( self, _index = 0, _len = 1 ):
		return self[ 0 : _index - 1 ] + self[ _index + _len - 1 : ]

__builtin__.str = TheirString

Granted, the second example isn’t necessary when snipping chars from the left or right of the string because strip r / l already does that. So not enough research has gone in to see a user-friendly / readable function exists for these cases… Now to snip some from the center, that’s different… it could use another function name, but the function above for snip strange to follow… it doesn’t just snip… it can snip chars, duplicate with offset while still snipping at least 1 char, etc… it isn’t predictable enough and therefore not enough thought has gone into it for it to be named snip… Never trust user input, and this function doesn’t do what it advertises so it is a terrible example of what should be added and a perfect example of what not to do…

If Python devs added a snip from char for len chars function they’d ensure it’d do exactly that with no unexpected behavior while allowing - offsets for the starting character, or -len to snip from the starting char in reverse ( and they’d likely NOT remove the 10th char, for instance if using start at 10 and remove -1 so the 9th char would be removed… and for 1 the 10th char would be removed )…

However, because MyString is str, as stated, TheirString extending str actually extends MyString. so it doesn’t matter which order they are called…

Granted if they add reverse and use a for loop to copy each string to a new string in reverse order - that’s definitely bad because there’s already a built-in method to do it more elegantly but not in a user-readable ( or beginner readable ) way…

0 Likes

#10

What do you mean it doesn’t work?

mystr.py

class MyStr(str):
   def reverse(self):
      return self[::-1]

myplugin.py

import sublime
import sublime_plugin
from .mystr import MyStr as str


class MyStringCommand(sublime_plugin.ApplicationCommand):
    def run(self):
        test = str('test')
        sublime.message_dialog(test.reverse())

Execute command

sublime.run_command('my_string')

If you are expecting all of your strings to magically become mystr ("test".revese()), that will not happen. You’ll simply have to cast your strings that are not explicitly of that type as done in the plugin.

If you find that annoying, simply write a reverse function:

def reverse(string):
    return string[::-1]

Easy to read, and you don’t have to cast anything.

But as a plugin writer, I don’t want to have to debug some edge case because my plugin somehow adopted the “acecool_str” implementation. I know you think it will be fine, but let’s be honest, you have no idea all the various, advanced ways someone might be exploiting Python strings, and if your modifying all builtin strings will break things.

For the sake of everyone in this community, please don’t modify builtins. I would personally boycott any plugin that had the audacity to do such a thing.

3 Likes

#11

I have to reiterate that there is no way for you to know how monkeypatching builtin objects will affect other packages. It is always dangerous and it cannot be made safe.

If you have a sandboxed environment that your patches cannot escape, then you can do whatever you want. Or, if you’re setting up a “master” environment and expect everyone else to write their code for your patched environment, then that can work as well. But your Sublime plugins share an environment with other packages that implicitly assume a standard Python environment. It is entirely reasonable for other authors to make that assumption and unreasonable for any package author to violate it.

In the end, the point is moot. It doesn’t appear that Sublime’s Python runtime will allow you do modify builtins as you want to do. It is unlikely that the devs would deliberately add support for this, and very likely that a package that did somehow manage to monkeypatch the standard builtin types would be rejected.

Why not just write a reverse function? You could invoke it as reverse('Testing'). There’s no need to have a wrapper class.

3 Likes